添加项目文件。
This commit is contained in:
206
src/BRS.Common.Device/BRS.Common.Device.csproj
Normal file
206
src/BRS.Common.Device/BRS.Common.Device.csproj
Normal file
@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\packages\PostSharp.6.2.7\build\PostSharp.props" Condition="Exists('..\..\packages\PostSharp.6.2.7\build\PostSharp.props')" />
|
||||
<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>{987308DD-8BAA-463A-94E2-77D62E01A5BF}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>BRS.Common.Device</RootNamespace>
|
||||
<AssemblyName>BRS.Common.Device</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug1|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\Debug1\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug1|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug1\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=4.9.4.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Autofac.4.9.4\lib\net45\Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MrAdvice, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c0e7e6eab6f293d8, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\MrAdvice.2.9.7\lib\net40-client\MrAdvice.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.7.1\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.7.0.0-preview.2.22152.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<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="Base\DeviceBase.cs" />
|
||||
<Compile Include="DeviceBase\AGVBase.cs" />
|
||||
<Compile Include="DeviceBase\CameraBase.cs" />
|
||||
<Compile Include="DeviceBase\ForceSensorBase.cs" />
|
||||
<Compile Include="DeviceBase\IODeviceBase.cs" />
|
||||
<Compile Include="DeviceBase\RobotBase.cs" />
|
||||
<Compile Include="DeviceBase\SerialPortBase.cs" />
|
||||
<Compile Include="DeviceBase\VisionEngineBase.cs" />
|
||||
<Compile Include="DeviceBase\MessageQueueBase.cs" />
|
||||
<Compile Include="DeviceBase\ModbusASCIICommBase.cs" />
|
||||
<Compile Include="DeviceBase\MotionCardBase.cs" />
|
||||
<Compile Include="DeviceBase\PLCBase.cs" />
|
||||
<Compile Include="DeviceBase\RS-232CommBase.cs" />
|
||||
<Compile Include="DeviceBase\TcpCommBase.cs" />
|
||||
<Compile Include="Helper\AspectHelper.cs" />
|
||||
<Compile Include="Helper\SerialPortHelper.cs" />
|
||||
<Compile Include="Interface\IMotion.cs" />
|
||||
<Compile Include="Interface\IVibrationSupplier.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Calibration\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BRS.Common.Model\BRS.Common.Model.csproj">
|
||||
<Project>{1a3cbfe7-3f78-42c3-95c5-10360450dbea}</Project>
|
||||
<Name>BRS.Common.Model</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BRS.UI.Model.Winform\BRS.UI.Model.Winform.csproj">
|
||||
<Project>{741f6491-57c7-479a-b391-09bba9fba9dc}</Project>
|
||||
<Name>BRS.UI.Model.Winform</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\..\packages\MrAdvice.2.9.7\build\MrAdvice.targets" Condition="Exists('..\..\packages\MrAdvice.2.9.7\build\MrAdvice.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\MrAdvice.2.9.7\build\MrAdvice.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\MrAdvice.2.9.7\build\MrAdvice.targets'))" />
|
||||
</Target>
|
||||
<!-- 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>
|
401
src/BRS.Common.Device/Base/DeviceBase.cs
Normal file
401
src/BRS.Common.Device/Base/DeviceBase.cs
Normal file
@ -0,0 +1,401 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class DeviceBase : IDevice
|
||||
{
|
||||
#region Event
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public Action<DateTime, Exception> OnExceptionOccured { get; set; }
|
||||
//public event Action<DateTime, LogLevel, string> OnLog;
|
||||
public event Action<LogMsg> OnLog;
|
||||
public event Action<IDevice, DeviceState> OnDeviceStateChanged;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region field
|
||||
int RetryTime = 3;
|
||||
/// <summary>
|
||||
/// 和设备暂停状态关联的信号量
|
||||
/// </summary>
|
||||
private readonly ManualResetEvent pauseHandle = new ManualResetEvent(true);
|
||||
readonly Timer stateChangedTimer;
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region Property
|
||||
#region State
|
||||
private EnumHelper.DeviceState _currentStateToBe = EnumHelper.DeviceState.DSUninit;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当前设备状态
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
internal EnumHelper.DeviceState CurrentStateToBe
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentStateToBe;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _currentStateToBe)
|
||||
{
|
||||
var initialState = _currentStateToBe;
|
||||
_currentStateToBe = value;
|
||||
|
||||
if (_currentStateToBe != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
OnStateChanged(initialState);
|
||||
}
|
||||
else
|
||||
{
|
||||
stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private EnumHelper.DeviceState initialState = EnumHelper.DeviceState.DSUninit;
|
||||
private EnumHelper.DeviceState _currentState = EnumHelper.DeviceState.DSUninit;
|
||||
public EnumHelper.DeviceState CurrentState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentState;
|
||||
}
|
||||
set
|
||||
{
|
||||
_currentState = value;
|
||||
|
||||
if (value != EnumHelper.DeviceState.TBD)
|
||||
{
|
||||
OnDeviceStateChanged?.Invoke(this, _currentState);
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState"));
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// initialState = _currentState;
|
||||
//}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 设备标识符 从数据库获取
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备名称 从数据库获取
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
private IInitialConfig initialConfig = null;
|
||||
/// <summary>
|
||||
/// 设备初始化配置 从数据库获取
|
||||
/// </summary>
|
||||
public virtual IInitialConfig InitialConfig
|
||||
{
|
||||
get => initialConfig;
|
||||
set
|
||||
{
|
||||
initialConfig = value;
|
||||
Id = initialConfig.Id;
|
||||
Name = initialConfig.Name;
|
||||
|
||||
LoggerHelper.LogPath = initialConfig.LogPath;
|
||||
LoggerHelper.LogPrefix = initialConfig.Name;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
public DeviceBase()
|
||||
{
|
||||
RegisterFileWriterException();
|
||||
stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设备抽象方法
|
||||
protected virtual void Init()
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Assist, $"{Name}初始化完成");
|
||||
}
|
||||
|
||||
protected abstract void Pause();
|
||||
|
||||
protected abstract void Resume();
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Assist, $"{Name}启动");
|
||||
}
|
||||
|
||||
protected virtual void Stop()
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Assist, $"{Name}停止");
|
||||
}
|
||||
|
||||
//public abstract void AttachToProcess(IProcess process);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 常用操作封装方法
|
||||
/// </summary>
|
||||
/// <param name="opConfig"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ResponseMessage RunWrap(IOperationConfig opConfig)
|
||||
{
|
||||
ResponseMessage msg = new ResponseMessage();
|
||||
msg.Message = "设备基类默认操作";
|
||||
return msg;
|
||||
}
|
||||
|
||||
#region 状态切换
|
||||
[DeviceExceptionAspect]
|
||||
public void StateChange(EnumHelper.DeviceState stateToBe)
|
||||
{
|
||||
if (CurrentState == stateToBe)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stateToBe.CheckPreStateValid((int)CurrentStateToBe))
|
||||
{
|
||||
string currentStateStr = CurrentStateToBe.GetEnumDescription();
|
||||
string stateToBeStr = stateToBe.GetEnumDescription();
|
||||
throw new ProcessException($"{InitialConfig.Name}设备的当前状态为{currentStateStr},无法切换至{stateToBeStr}");
|
||||
}
|
||||
|
||||
CurrentState = EnumHelper.DeviceState.TBD;
|
||||
CurrentStateToBe = stateToBe;
|
||||
}
|
||||
|
||||
[DeviceExceptionAspect]
|
||||
private void OnStateChanged(EnumHelper.DeviceState initialState)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CurrentStateToBe != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CurrentState == EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ProcessException($"{InitialConfig.Name}设备操作超时");
|
||||
}
|
||||
}
|
||||
|
||||
if (RetryTime >= 0)
|
||||
{
|
||||
if (initialState == CurrentStateToBe)
|
||||
{
|
||||
CurrentState = CurrentStateToBe;
|
||||
return;
|
||||
}
|
||||
|
||||
#region 状态切换操作
|
||||
switch (CurrentStateToBe)
|
||||
{
|
||||
case EnumHelper.DeviceState.DSInit:
|
||||
if (initialState == EnumHelper.DeviceState.DSOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Init();
|
||||
}
|
||||
break;
|
||||
case EnumHelper.DeviceState.DSOpen:
|
||||
if (initialState == EnumHelper.DeviceState.DSInit)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
else if (initialState == EnumHelper.DeviceState.DSPause)
|
||||
{
|
||||
Resume();
|
||||
pauseHandle.Set();
|
||||
}
|
||||
break;
|
||||
case EnumHelper.DeviceState.DSPause:
|
||||
pauseHandle.Reset();
|
||||
Pause();
|
||||
break;
|
||||
case EnumHelper.DeviceState.DSClose:
|
||||
if (initialState != DeviceState.DSUninit)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
RetryTime = 3;
|
||||
CurrentState = CurrentStateToBe;
|
||||
#endregion
|
||||
}
|
||||
|
||||
stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RetryTime--;
|
||||
if (RetryTime > 0)
|
||||
{
|
||||
OnStateChanged(initialState);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
RetryTime = 3;
|
||||
throw new ProcessException($"设备{InitialConfig.Name}的{CurrentStateToBe.GetEnumDescription()}操作重复3次失败", ex, ExceptionLevel.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckDeviceOpTimeOut(object state)
|
||||
{
|
||||
stateChangedTimer?.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
if (CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
StateChange(EnumHelper.DeviceState.DSExcept);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 日志处理
|
||||
private void RegisterFileWriterException()
|
||||
{
|
||||
LoggerHelper.OnLogExceptionRaised -= LoggerHelper_OnLogExceptionRaised;
|
||||
CSVHelper.OnCSVExceptionRaised -= LoggerHelper_OnLogExceptionRaised;
|
||||
|
||||
LoggerHelper.OnLogExceptionRaised += LoggerHelper_OnLogExceptionRaised;
|
||||
CSVHelper.OnCSVExceptionRaised += LoggerHelper_OnLogExceptionRaised;
|
||||
}
|
||||
public CSVHelper CSVHelper { get; set; } = new CSVHelper();
|
||||
|
||||
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
||||
|
||||
public virtual void LogAsync(LogMsg msg)
|
||||
{
|
||||
msg.MsgSource = Name;
|
||||
msg.ThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
//OnLog?.BeginInvoke(msg, null, null);
|
||||
OnLog?.Invoke(msg);
|
||||
|
||||
if (InitialConfig.IsEnableLog)
|
||||
{
|
||||
LoggerHelper.LogAsync(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||||
}
|
||||
|
||||
|
||||
private void LoggerHelper_OnLogExceptionRaised(DateTime dt, string msg)
|
||||
{
|
||||
OnLog?.Invoke(new LogMsg(dt, LogLevel.Error, msg));
|
||||
}
|
||||
/// <summary>
|
||||
/// CSV异步数据输出
|
||||
/// </summary>
|
||||
/// <param name="csvFile">CSV输出文件的文件全路径</param>
|
||||
/// <param name="csvData">CSV输出数据</param>
|
||||
/// <param name="csvHead">CSV文件表头</param>
|
||||
public virtual void CSVRecordAsync(string csvFile, string csvData, string csvHead = "")
|
||||
{
|
||||
CSVHelper.CSVOutputAsync(csvFile, csvData, csvHead);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 报警记录
|
||||
object _alarmLock = new object();
|
||||
protected virtual async void SaveAlarmCSVAsync(DateTime now, string deviceName, IWarningSet ws)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
LogAsync(now, LogLevel.Warning, $"{ws.WarningCode}-{ws.WarningDescription} {(ws.CurrentStatus ? "发生" : "取消")}");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(this.InitialConfig.LogPath) || !InitialConfig.IsEnableCSV)
|
||||
return;
|
||||
|
||||
string path = Path.Combine(InitialConfig.LogPath, $"Alarm_{Name}_{now.ToString("yyyyMMdd")}.csv");
|
||||
string head = "Time,Source,AlarmCode,AlarmDescription,AlarmStatus";
|
||||
string data = $"{now.ToString("HH:mm:ss.fff")},{deviceName},{ws.WarningCode},{ws.WarningDescription},{(ws.CurrentStatus ? "报警发生" : "报警取消")}";
|
||||
CSVRecordAsync(path, data, head);
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // 要检测冗余调用
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
//释放托管状态(托管对象)。
|
||||
stateChangedTimer?.Dispose();
|
||||
pauseHandle?.Dispose();
|
||||
}
|
||||
|
||||
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
|
||||
// TODO: 将大型字段设置为 null。
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
|
||||
// ~DeviceBase()
|
||||
// {
|
||||
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// 添加此代码以正确实现可处置模式。
|
||||
public void Dispose()
|
||||
{
|
||||
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
|
||||
Dispose(true);
|
||||
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
85
src/BRS.Common.Device/Base/DeviceConfigBase.cs
Normal file
85
src/BRS.Common.Device/Base/DeviceConfigBase.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Bro.Common.Base
|
||||
{
|
||||
public class OperationConfigBase : IOperationConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 输入参数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Category("输入配置")]
|
||||
[Description("输入参数配置")]
|
||||
[TypeConverter(typeof(SimpleCollectionConvert<int>))]
|
||||
public List<int> InputPara { get; set; } = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// 异常反馈值
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("异常反馈值")]
|
||||
public int ExceptionValue { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 发生异常时的重新尝试次数
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("发生异常时的重新尝试次数")]
|
||||
public int ReTryTimes { get; set; } = 3;
|
||||
}
|
||||
|
||||
public abstract class InitialConfigBase : IInitialConfig
|
||||
{
|
||||
[Category("通用配置")]
|
||||
[Description("设备索引")]
|
||||
[ReadOnly(true)]
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
[Category("通用配置")]
|
||||
[Description("设备名称")]
|
||||
public string Name { get; set; } = "UnNamed";
|
||||
|
||||
/// <summary>
|
||||
/// 设备是否启用
|
||||
/// </summary>
|
||||
[Category("通用配置")]
|
||||
[Description("设备是否启用")]
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 设备类型 在具体设备基类中看是否需要开放重写
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public virtual string DriverType { get; set; } = "";
|
||||
|
||||
[Category("日志配置")]
|
||||
[Description("日志记录目录")]
|
||||
[Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))]
|
||||
public string LogPath { get; set; } = "";
|
||||
|
||||
[Category("日志配置")]
|
||||
[Description("true:启用日志记录 false:不启用日志记录")]
|
||||
public bool IsEnableLog { get; set; } = false;
|
||||
|
||||
public virtual List<string> GetHalconToolPathList()
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
public InitialConfigBase()
|
||||
{
|
||||
var attr = this.GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
this.DriverType = attr.TypeCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
190
src/BRS.Common.Device/Base/InputConfigBase.cs
Normal file
190
src/BRS.Common.Device/Base/InputConfigBase.cs
Normal file
@ -0,0 +1,190 @@
|
||||
using Bro.Common.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Bro.Common.Base
|
||||
{
|
||||
public class InputConfigBase : IInputConfig
|
||||
{
|
||||
//public InputConfigBase()
|
||||
//{
|
||||
// StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
//}
|
||||
|
||||
//[JsonIgnore]
|
||||
//public AutoResetEvent InputHanlder { get; set; } = new AutoResetEvent(false);
|
||||
|
||||
// [JsonIgnore]
|
||||
//public string IConfigId = Guid.NewGuid().ToString();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public Dictionary<string, AutoResetEvent> InputHanlderDict { get; set; } = new Dictionary<string, AutoResetEvent>();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public Dictionary<string, bool> InputFlagDict { get; set; } = new Dictionary<string, bool>();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public ConcurrentDictionary<string, AutoResetEvent> InputHanlderDict { get; set; } = new ConcurrentDictionary<string, AutoResetEvent>();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public ConcurrentDictionary<string, bool> InputFlagDict { get; set; } = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
[JsonIgnore]
|
||||
public bool BoundFlag { get; set; } = false;
|
||||
|
||||
public bool IsInputNeed { get; set; } = false;
|
||||
|
||||
public string InputMethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 第三方设备输入参数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public dynamic InputPara { get; set; }
|
||||
|
||||
private string processId;
|
||||
[JsonIgnore]
|
||||
public string ProcessId
|
||||
{
|
||||
get
|
||||
{
|
||||
return processId;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (processId != value)
|
||||
{
|
||||
//仅在工序编号赋值后建立消息连接
|
||||
processId = value;
|
||||
|
||||
//if (conn == null)
|
||||
//{
|
||||
// conn = new HubConnection(GlobalVar.SignalRServer);
|
||||
|
||||
// proxy = conn.CreateHubProxy("DeviceHub");
|
||||
// proxy.On<InputPara>("OnDeviceInput", OnDeviceInput);
|
||||
|
||||
// conn.Start().Wait();
|
||||
//}
|
||||
//lock (this)
|
||||
{
|
||||
//InputHanlderDict[processId] = new AutoResetEvent(false);
|
||||
//InputFlagDict[processId] = false;
|
||||
//InputHanlderDict.AddOrUpdate(processId, new AutoResetEvent(false), (a, b) => { return new AutoResetEvent(false); });
|
||||
//InputFlagDict.AddOrUpdate(processId, false, (a, b) => { return false; });
|
||||
|
||||
InputHandle = new AutoResetEvent(false);
|
||||
//StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
}
|
||||
|
||||
//if (StateMachine.OnDeviceInput != null)
|
||||
//{
|
||||
// var list = StateMachine.OnDeviceInput.GetInvocationList().ToList();
|
||||
// if (list != null)
|
||||
// {
|
||||
// if (!list.Any(d =>
|
||||
// {
|
||||
// InputConfigBase icb = d.Target as InputConfigBase;
|
||||
// return icb.ProcessId == ProcessId;
|
||||
// }))
|
||||
// {
|
||||
// StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
//StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
//PubSubCenter.GetInstance().Subscribe(processId, OnDeviceInput);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public AutoResetEvent InputHandle { get; set; } = new AutoResetEvent(false);
|
||||
|
||||
public string ProcessName { get; set; }
|
||||
|
||||
|
||||
|
||||
//HubConnection conn;
|
||||
//IHubProxy proxy;
|
||||
|
||||
/// <summary>
|
||||
/// 适用于第三方的信号输入
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
//private object OnDeviceInput(ISubscriber sub, object param1, object param2)
|
||||
private void OnDeviceInput(InputPara obj)
|
||||
{
|
||||
//Debug.WriteLine(DateTime.Now.ToString("mm:ss.fff") + "\t输入流程:" + obj.ProcessId + ";\t本流程编号:" + ProcessId);
|
||||
//输入参数必须有一个字段是ProcessId,保存工序编号
|
||||
//string processId = obj.ProcessId;
|
||||
|
||||
//if (obj.ProcessId == ProcessId)
|
||||
//{
|
||||
// InputPara = obj.ParaObj;
|
||||
// InputHanlderDict[].Set();
|
||||
// BoundFlag = false;
|
||||
//}
|
||||
|
||||
//InputPara obj = param1 as InputPara;
|
||||
|
||||
//lock (this)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (InputHanlderDict.Keys.Contains(obj.ProcessId))
|
||||
if (ProcessId == obj.ProcessId)
|
||||
{
|
||||
//Debug.WriteLine(DateTime.Now.ToString("mm:ss.fff") + "\t流程编号:" + obj.ProcessId);
|
||||
//InputHanlderDict[obj.ProcessId].Set();
|
||||
//InputFlagDict[obj.ProcessId] = true;
|
||||
InputHandle.Set();
|
||||
//InputHanlderDict.Remove(obj.ProcessId);
|
||||
//StateMachine.OnDeviceInput -= OnDeviceInput;
|
||||
//PubSubCenter.GetInstance().RemoveSubscriber(ProcessId, OnDeviceInput);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
//return null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
//foreach (var handle in InputHanlderDict)
|
||||
//{
|
||||
// handle.Value.Set();
|
||||
//}
|
||||
|
||||
//StateMachine.OnDeviceInput -= OnDeviceInput;
|
||||
|
||||
//InputHanlderDict = new ConcurrentDictionary<string, AutoResetEvent>();
|
||||
//InputFlagDict = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
//GC.Collect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class InputPara : IProcessID
|
||||
{
|
||||
public string ProcessId { get; set; }
|
||||
|
||||
//[DataMember]
|
||||
public dynamic ParaObj { get; set; }
|
||||
|
||||
public string ProcessName { get; set; }
|
||||
}
|
||||
}
|
85
src/BRS.Common.Device/Base/OperationConfigBase.cs
Normal file
85
src/BRS.Common.Device/Base/OperationConfigBase.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Bro.Common.Helper.EnumHelper;
|
||||
|
||||
namespace Bro.Common.Base
|
||||
{
|
||||
//[Device("Base", "基础操作配置", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class OperationConfigBase : IOperationConfig
|
||||
{
|
||||
////[JsonIgnore]
|
||||
//public IDeviceConfig DeviceConfig { get; set; }
|
||||
|
||||
////[JsonIgnore]
|
||||
//public IInputConfig InputConfig { get; set; }
|
||||
|
||||
//public string OutputMethodName { get; set; }
|
||||
|
||||
////[JsonIgnore]
|
||||
//public string ProcessId { get; set; }
|
||||
|
||||
//public string ProcessName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public virtual int ResultOutput { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 输入参数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public List<int> InputPara { get; set; }
|
||||
|
||||
|
||||
[Category("启用配置")]
|
||||
[Description("true:启用该配置执行操作;false:不启用该配置,不执行操作")]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 异常反馈值
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("异常反馈值")]
|
||||
public int ExceptionValue { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 发生异常时的重新尝试次数
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("发生异常时的重新尝试次数")]
|
||||
public int ReTryTimes { get; set; } = 3;
|
||||
|
||||
///// <summary>
|
||||
///// 发生异常多次后向PLC报警
|
||||
///// </summary>
|
||||
//[Category("异常反馈设置")]
|
||||
//[Description("发生异常多次后向PLC报警")]
|
||||
//public int PLCWarningTimes { get; set; } = 0;
|
||||
|
||||
///// <summary>
|
||||
///// 向PLC报警的报警类别
|
||||
///// </summary>
|
||||
//[Category("异常反馈设置")]
|
||||
//[Description("向PLC报警的报警类别")]
|
||||
//public WarningFromPC WarningType { get; set; } = WarningFromPC.UnknowError;
|
||||
|
||||
///// <summary>
|
||||
///// 14 (2+4+8)表示全部采用上道工序输出配置
|
||||
///// </summary>
|
||||
//public int ConfigPreset { get; set; } = 0;
|
||||
}
|
||||
|
||||
public class OperationConfigCommon : OperationConfigBase
|
||||
{
|
||||
[ConfigOutputResource("OutputResultCommon")]
|
||||
public override int ResultOutput { get; set; }
|
||||
}
|
||||
}
|
39
src/BRS.Common.Device/Base/ProcessBase.cs
Normal file
39
src/BRS.Common.Device/Base/ProcessBase.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using Bro.Device.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Bro.Device.Common.Helper;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Common.Base
|
||||
{
|
||||
public class ProcessBase : IProcess
|
||||
{
|
||||
private EnumHelper.ProcessState _currentState = EnumHelper.ProcessState.Idel;
|
||||
|
||||
[NotMapped]
|
||||
public EnumHelper.ProcessState CurrentState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentState;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _currentState)
|
||||
{
|
||||
_currentState = value;
|
||||
OnStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnStateChanged()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
using Bro.Common.Base;
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Model;
|
||||
using Bro.Common.Model.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bro.Common.Calibration
|
||||
{
|
||||
[Device("CalibrationDynamic9Point", "动态9点标定配置", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class CalibrationDynamic9PointConfig : OperationConfigBase, IHalconToolPath
|
||||
{
|
||||
[Category("交互设置")]
|
||||
[Description("电气触发标定动作地址,设置为1时触发标定动作。实际地址。")]
|
||||
public int TriggerAddress { get; set; }
|
||||
|
||||
[Category("交互设置")]
|
||||
[Description("平台位置数据在监视数据中起始地址索引,XY坐标,连续4位。从0开始。")]
|
||||
public int LocationStartAddressIndex { get; set; }
|
||||
|
||||
[Category("标定结果")]
|
||||
[Description("标定结果集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<CalibrationResult>), typeof(UITypeEditor))]
|
||||
public NoticedList<CalibrationResult> Results { get; set; } = new NoticedList<CalibrationResult>();
|
||||
|
||||
[Category("标定配置")]
|
||||
[Description("标定步骤总数,一般9次")]
|
||||
public int TotalSteps { get; set; } = 9;
|
||||
|
||||
[Category("标定配置")]
|
||||
[Description("相机操作配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public CameraOprerationConfigBase CameraOpConfig { get; set; } = new CameraOprerationConfigBase();
|
||||
|
||||
public List<string> GetHalconToolPathList()
|
||||
{
|
||||
return CameraOpConfig.GetHalconToolPathList();
|
||||
}
|
||||
}
|
||||
|
||||
public class CalibrationResult : IComplexDisplay, INotifyPropertyChanged
|
||||
{
|
||||
//private Bitmap image = null;
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public Bitmap Image { get; set; }
|
||||
//{
|
||||
// get => image;
|
||||
// set
|
||||
// {
|
||||
// image = value;
|
||||
|
||||
// if (value != null)
|
||||
// {
|
||||
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Image"));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
[Category("标定结果")]
|
||||
[Description("图像点位|平台点位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public CalibrationPoint PointResult { get; set; } = new CalibrationPoint();
|
||||
|
||||
[Category("标定结果")]
|
||||
[Description("步骤序号,从1开始")]
|
||||
public int StepNum { get; set; } = 1;
|
||||
|
||||
private bool isDone = false;
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public bool IsDone
|
||||
{
|
||||
get => isDone;
|
||||
set
|
||||
{
|
||||
isDone = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsDone"));
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public CustomizedPoint ImagePoint
|
||||
{
|
||||
set
|
||||
{
|
||||
PointResult.U = value.X;
|
||||
PointResult.V = value.Y;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public CustomizedPoint PlatPoint
|
||||
{
|
||||
set
|
||||
{
|
||||
PointResult.X = value.X;
|
||||
PointResult.Y = value.Y;
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return $"{StepNum}:{(IsDone == false ? "未完成" : ($"{PointResult.GetDisplayText()}"))}";
|
||||
//return $"{StepNum}:{PointResult.GetDisplayText()}";
|
||||
}
|
||||
}
|
||||
}
|
353
src/BRS.Common.Device/Calibration/CalibrationDynamic9PointFrm.Designer.cs
generated
Normal file
353
src/BRS.Common.Device/Calibration/CalibrationDynamic9PointFrm.Designer.cs
generated
Normal file
@ -0,0 +1,353 @@
|
||||
namespace Bro.Common.Calibration
|
||||
{
|
||||
partial class CalibrationDynamic9PointFrm
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.splitMain = new System.Windows.Forms.SplitContainer();
|
||||
this.plOpBtns = new System.Windows.Forms.Panel();
|
||||
this.chkManualConfirm = new System.Windows.Forms.CheckBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.chkContinueMode = new System.Windows.Forms.CheckBox();
|
||||
this.btnCalcuMatrix = new System.Windows.Forms.Button();
|
||||
this.btnContinueCalib = new System.Windows.Forms.Button();
|
||||
this.btnSnap = new System.Windows.Forms.Button();
|
||||
this.btnStepRun = new System.Windows.Forms.Button();
|
||||
this.btnClearResult = new System.Windows.Forms.Button();
|
||||
this.btnStartCalib = new System.Windows.Forms.Button();
|
||||
this.splitConfig = new System.Windows.Forms.SplitContainer();
|
||||
this.lvResults = new System.Windows.Forms.ListView();
|
||||
this.clIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.clResult = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.pgCameraConfig = new System.Windows.Forms.PropertyGrid();
|
||||
this.plImage = new System.Windows.Forms.Panel();
|
||||
this.stspStatus = new System.Windows.Forms.StatusStrip();
|
||||
this.tsslStepHint = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.tsslInfo = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitMain)).BeginInit();
|
||||
this.splitMain.Panel1.SuspendLayout();
|
||||
this.splitMain.Panel2.SuspendLayout();
|
||||
this.splitMain.SuspendLayout();
|
||||
this.plOpBtns.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitConfig)).BeginInit();
|
||||
this.splitConfig.Panel1.SuspendLayout();
|
||||
this.splitConfig.Panel2.SuspendLayout();
|
||||
this.splitConfig.SuspendLayout();
|
||||
this.stspStatus.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// splitMain
|
||||
//
|
||||
this.splitMain.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitMain.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
|
||||
this.splitMain.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitMain.Name = "splitMain";
|
||||
//
|
||||
// splitMain.Panel1
|
||||
//
|
||||
this.splitMain.Panel1.Controls.Add(this.plOpBtns);
|
||||
this.splitMain.Panel1.Controls.Add(this.splitConfig);
|
||||
//
|
||||
// splitMain.Panel2
|
||||
//
|
||||
this.splitMain.Panel2.Controls.Add(this.plImage);
|
||||
this.splitMain.Panel2.Controls.Add(this.stspStatus);
|
||||
this.splitMain.Size = new System.Drawing.Size(828, 483);
|
||||
this.splitMain.SplitterDistance = 278;
|
||||
this.splitMain.TabIndex = 0;
|
||||
//
|
||||
// plOpBtns
|
||||
//
|
||||
this.plOpBtns.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.plOpBtns.Controls.Add(this.chkManualConfirm);
|
||||
this.plOpBtns.Controls.Add(this.label3);
|
||||
this.plOpBtns.Controls.Add(this.label2);
|
||||
this.plOpBtns.Controls.Add(this.label1);
|
||||
this.plOpBtns.Controls.Add(this.chkContinueMode);
|
||||
this.plOpBtns.Controls.Add(this.btnCalcuMatrix);
|
||||
this.plOpBtns.Controls.Add(this.btnContinueCalib);
|
||||
this.plOpBtns.Controls.Add(this.btnSnap);
|
||||
this.plOpBtns.Controls.Add(this.btnStepRun);
|
||||
this.plOpBtns.Controls.Add(this.btnClearResult);
|
||||
this.plOpBtns.Controls.Add(this.btnStartCalib);
|
||||
this.plOpBtns.Location = new System.Drawing.Point(3, 323);
|
||||
this.plOpBtns.Name = "plOpBtns";
|
||||
this.plOpBtns.Size = new System.Drawing.Size(272, 158);
|
||||
this.plOpBtns.TabIndex = 1;
|
||||
//
|
||||
// chkManualConfirm
|
||||
//
|
||||
this.chkManualConfirm.AutoSize = true;
|
||||
this.chkManualConfirm.Location = new System.Drawing.Point(11, 132);
|
||||
this.chkManualConfirm.Name = "chkManualConfirm";
|
||||
this.chkManualConfirm.Size = new System.Drawing.Size(72, 16);
|
||||
this.chkManualConfirm.TabIndex = 3;
|
||||
this.chkManualConfirm.Text = "人工确认";
|
||||
this.chkManualConfirm.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(6, 117);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(257, 12);
|
||||
this.label3.TabIndex = 2;
|
||||
this.label3.Text = "------------------------------------------";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 76);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(257, 12);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "------------------------------------------";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(7, 35);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(257, 12);
|
||||
this.label1.TabIndex = 2;
|
||||
this.label1.Text = "------------------------------------------";
|
||||
//
|
||||
// chkContinueMode
|
||||
//
|
||||
this.chkContinueMode.AutoSize = true;
|
||||
this.chkContinueMode.Location = new System.Drawing.Point(90, 95);
|
||||
this.chkContinueMode.Name = "chkContinueMode";
|
||||
this.chkContinueMode.Size = new System.Drawing.Size(72, 16);
|
||||
this.chkContinueMode.TabIndex = 1;
|
||||
this.chkContinueMode.Text = "连续模式";
|
||||
this.chkContinueMode.UseVisualStyleBackColor = true;
|
||||
this.chkContinueMode.CheckedChanged += new System.EventHandler(this.chkContinueMode_CheckedChanged);
|
||||
//
|
||||
// btnCalcuMatrix
|
||||
//
|
||||
this.btnCalcuMatrix.Location = new System.Drawing.Point(168, 50);
|
||||
this.btnCalcuMatrix.Name = "btnCalcuMatrix";
|
||||
this.btnCalcuMatrix.Size = new System.Drawing.Size(93, 23);
|
||||
this.btnCalcuMatrix.TabIndex = 0;
|
||||
this.btnCalcuMatrix.Text = "标定结果运算";
|
||||
this.btnCalcuMatrix.UseVisualStyleBackColor = true;
|
||||
this.btnCalcuMatrix.Click += new System.EventHandler(this.btnCalcuMatrix_Click);
|
||||
//
|
||||
// btnContinueCalib
|
||||
//
|
||||
this.btnContinueCalib.Location = new System.Drawing.Point(87, 128);
|
||||
this.btnContinueCalib.Name = "btnContinueCalib";
|
||||
this.btnContinueCalib.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnContinueCalib.TabIndex = 0;
|
||||
this.btnContinueCalib.Text = "继续标定";
|
||||
this.btnContinueCalib.UseVisualStyleBackColor = true;
|
||||
this.btnContinueCalib.Visible = false;
|
||||
this.btnContinueCalib.Click += new System.EventHandler(this.btnContinueCalib_Click);
|
||||
//
|
||||
// btnSnap
|
||||
//
|
||||
this.btnSnap.Location = new System.Drawing.Point(8, 91);
|
||||
this.btnSnap.Name = "btnSnap";
|
||||
this.btnSnap.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnSnap.TabIndex = 0;
|
||||
this.btnSnap.Text = "拍 照";
|
||||
this.btnSnap.UseVisualStyleBackColor = true;
|
||||
this.btnSnap.Click += new System.EventHandler(this.btnSnap_Click);
|
||||
//
|
||||
// btnStepRun
|
||||
//
|
||||
this.btnStepRun.Location = new System.Drawing.Point(8, 50);
|
||||
this.btnStepRun.Name = "btnStepRun";
|
||||
this.btnStepRun.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnStepRun.TabIndex = 0;
|
||||
this.btnStepRun.Text = "单步运算";
|
||||
this.btnStepRun.UseVisualStyleBackColor = true;
|
||||
this.btnStepRun.Click += new System.EventHandler(this.btnStepRun_Click);
|
||||
//
|
||||
// btnClearResult
|
||||
//
|
||||
this.btnClearResult.Location = new System.Drawing.Point(168, 9);
|
||||
this.btnClearResult.Name = "btnClearResult";
|
||||
this.btnClearResult.Size = new System.Drawing.Size(93, 23);
|
||||
this.btnClearResult.TabIndex = 0;
|
||||
this.btnClearResult.Text = "清除结果";
|
||||
this.btnClearResult.UseVisualStyleBackColor = true;
|
||||
this.btnClearResult.Click += new System.EventHandler(this.btnClearResult_Click);
|
||||
//
|
||||
// btnStartCalib
|
||||
//
|
||||
this.btnStartCalib.Location = new System.Drawing.Point(8, 9);
|
||||
this.btnStartCalib.Name = "btnStartCalib";
|
||||
this.btnStartCalib.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnStartCalib.TabIndex = 0;
|
||||
this.btnStartCalib.Text = "开始标定";
|
||||
this.btnStartCalib.UseVisualStyleBackColor = true;
|
||||
this.btnStartCalib.Click += new System.EventHandler(this.btnStartCalib_Click);
|
||||
//
|
||||
// splitConfig
|
||||
//
|
||||
this.splitConfig.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.splitConfig.FixedPanel = System.Windows.Forms.FixedPanel.Panel2;
|
||||
this.splitConfig.Location = new System.Drawing.Point(3, 0);
|
||||
this.splitConfig.Name = "splitConfig";
|
||||
this.splitConfig.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
||||
//
|
||||
// splitConfig.Panel1
|
||||
//
|
||||
this.splitConfig.Panel1.Controls.Add(this.lvResults);
|
||||
//
|
||||
// splitConfig.Panel2
|
||||
//
|
||||
this.splitConfig.Panel2.Controls.Add(this.pgCameraConfig);
|
||||
this.splitConfig.Size = new System.Drawing.Size(272, 317);
|
||||
this.splitConfig.SplitterDistance = 104;
|
||||
this.splitConfig.TabIndex = 0;
|
||||
//
|
||||
// lvResults
|
||||
//
|
||||
this.lvResults.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.clIndex,
|
||||
this.clResult});
|
||||
this.lvResults.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lvResults.FullRowSelect = true;
|
||||
this.lvResults.Location = new System.Drawing.Point(0, 0);
|
||||
this.lvResults.MultiSelect = false;
|
||||
this.lvResults.Name = "lvResults";
|
||||
this.lvResults.Size = new System.Drawing.Size(272, 104);
|
||||
this.lvResults.TabIndex = 0;
|
||||
this.lvResults.UseCompatibleStateImageBehavior = false;
|
||||
this.lvResults.View = System.Windows.Forms.View.Details;
|
||||
this.lvResults.SelectedIndexChanged += new System.EventHandler(this.lvConfigs_SelectedIndexChanged);
|
||||
//
|
||||
// clIndex
|
||||
//
|
||||
this.clIndex.Text = "序号";
|
||||
//
|
||||
// clResult
|
||||
//
|
||||
this.clResult.Text = "点位信息";
|
||||
this.clResult.Width = 200;
|
||||
//
|
||||
// pgCameraConfig
|
||||
//
|
||||
this.pgCameraConfig.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pgCameraConfig.Location = new System.Drawing.Point(0, 0);
|
||||
this.pgCameraConfig.Name = "pgCameraConfig";
|
||||
this.pgCameraConfig.Size = new System.Drawing.Size(272, 209);
|
||||
this.pgCameraConfig.TabIndex = 0;
|
||||
this.pgCameraConfig.ToolbarVisible = false;
|
||||
//
|
||||
// plImage
|
||||
//
|
||||
this.plImage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.plImage.Location = new System.Drawing.Point(-1, 0);
|
||||
this.plImage.Name = "plImage";
|
||||
this.plImage.Size = new System.Drawing.Size(547, 458);
|
||||
this.plImage.TabIndex = 1;
|
||||
//
|
||||
// stspStatus
|
||||
//
|
||||
this.stspStatus.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.tsslStepHint,
|
||||
this.tsslInfo});
|
||||
this.stspStatus.Location = new System.Drawing.Point(0, 461);
|
||||
this.stspStatus.Name = "stspStatus";
|
||||
this.stspStatus.Size = new System.Drawing.Size(546, 22);
|
||||
this.stspStatus.TabIndex = 0;
|
||||
this.stspStatus.Text = "statusStrip1";
|
||||
//
|
||||
// tsslStepHint
|
||||
//
|
||||
this.tsslStepHint.Name = "tsslStepHint";
|
||||
this.tsslStepHint.Size = new System.Drawing.Size(28, 17);
|
||||
this.tsslStepHint.Text = " ";
|
||||
//
|
||||
// tsslInfo
|
||||
//
|
||||
this.tsslInfo.Name = "tsslInfo";
|
||||
this.tsslInfo.Size = new System.Drawing.Size(28, 17);
|
||||
this.tsslInfo.Text = " ";
|
||||
//
|
||||
// CalibrationDynamic9PointFrm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(828, 483);
|
||||
this.Controls.Add(this.splitMain);
|
||||
this.Name = "CalibrationDynamic9PointFrm";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CalibrationDynamic9PointFrm_FormClosing);
|
||||
this.Load += new System.EventHandler(this.CtrlCalib9PDynamic_Load);
|
||||
this.splitMain.Panel1.ResumeLayout(false);
|
||||
this.splitMain.Panel2.ResumeLayout(false);
|
||||
this.splitMain.Panel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitMain)).EndInit();
|
||||
this.splitMain.ResumeLayout(false);
|
||||
this.plOpBtns.ResumeLayout(false);
|
||||
this.plOpBtns.PerformLayout();
|
||||
this.splitConfig.Panel1.ResumeLayout(false);
|
||||
this.splitConfig.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitConfig)).EndInit();
|
||||
this.splitConfig.ResumeLayout(false);
|
||||
this.stspStatus.ResumeLayout(false);
|
||||
this.stspStatus.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.SplitContainer splitMain;
|
||||
private System.Windows.Forms.Panel plOpBtns;
|
||||
private System.Windows.Forms.SplitContainer splitConfig;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox chkContinueMode;
|
||||
private System.Windows.Forms.Button btnCalcuMatrix;
|
||||
private System.Windows.Forms.Button btnSnap;
|
||||
private System.Windows.Forms.Button btnStepRun;
|
||||
private System.Windows.Forms.Button btnStartCalib;
|
||||
private System.Windows.Forms.Panel plImage;
|
||||
private System.Windows.Forms.StatusStrip stspStatus;
|
||||
private System.Windows.Forms.ToolStripStatusLabel tsslStepHint;
|
||||
private System.Windows.Forms.ToolStripStatusLabel tsslInfo;
|
||||
private System.Windows.Forms.ListView lvResults;
|
||||
private System.Windows.Forms.ColumnHeader clIndex;
|
||||
private System.Windows.Forms.ColumnHeader clResult;
|
||||
private System.Windows.Forms.PropertyGrid pgCameraConfig;
|
||||
private System.Windows.Forms.CheckBox chkManualConfirm;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Button btnContinueCalib;
|
||||
private System.Windows.Forms.Button btnClearResult;
|
||||
}
|
||||
}
|
403
src/BRS.Common.Device/Calibration/CalibrationDynamic9PointFrm.cs
Normal file
403
src/BRS.Common.Device/Calibration/CalibrationDynamic9PointFrm.cs
Normal file
@ -0,0 +1,403 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Interface;
|
||||
using Bro.Common.Base;
|
||||
using Bro.Common.UI;
|
||||
using Bro.Common.PubSub;
|
||||
using static Bro.Common.Helper.EnumHelper;
|
||||
using Bro.Common.Model;
|
||||
using HalconDotNet;
|
||||
using System.Threading;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Bro.Common.Calibration
|
||||
{
|
||||
public partial class CalibrationDynamic9PointFrm : Form
|
||||
{
|
||||
//PubSubCenter PubSubCenter = PubSubCenter.GetInstance();
|
||||
AutoResetEvent _confirmHandle = new AutoResetEvent(false);
|
||||
|
||||
public CalibrationDynamic9PointFrm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public CalibrationDynamic9PointFrm(CameraBase camera, PLCBase plc, CalibrationDynamic9PointConfig config)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Camera = camera;
|
||||
PLC = plc;
|
||||
Config = config as CalibrationDynamic9PointConfig;
|
||||
}
|
||||
|
||||
public CalibrationDynamic9PointConfig Config { get; set; }
|
||||
public CameraBase Camera { get; set; }
|
||||
public PLCBase PLC { get; set; }
|
||||
|
||||
public CalibrationDynamic9PointConfig GetConfig()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void LoadConfig(CalibrationDynamic9PointConfig config)
|
||||
{
|
||||
FillResults();
|
||||
|
||||
if (lvResults.Items.Count > 0)
|
||||
{
|
||||
lvResults.Items[0].Selected = true;
|
||||
}
|
||||
|
||||
pgCameraConfig.SelectedObject = config.CameraOpConfig;
|
||||
}
|
||||
|
||||
private void FillResults()
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(new Action(() => FillResults()));
|
||||
}
|
||||
else
|
||||
{
|
||||
lvResults.Items.Clear();
|
||||
for (int i = 0; i < Config.Results.Count; i++)
|
||||
{
|
||||
ListViewItem item = new ListViewItem(Config.Results[i].StepNum.ToString());
|
||||
item.SubItems.Add(Config.Results[i].GetDisplayText());
|
||||
item.Tag = Config.Results[i];
|
||||
item.BackColor = Config.Results[i].IsDone ? Color.GreenYellow : Color.Transparent;
|
||||
|
||||
//if (Config.Results[i].Image != null)
|
||||
//{
|
||||
// item.BackColor = Color.GreenYellow;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// item.BackColor = Color.Transparent;
|
||||
//}
|
||||
|
||||
Config.Results[i].PropertyChanged -= CtrlCalib9PDynamic_PropertyChanged;
|
||||
Config.Results[i].PropertyChanged += CtrlCalib9PDynamic_PropertyChanged;
|
||||
|
||||
lvResults.Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CtrlCalib9PDynamic_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
FillResults();
|
||||
}
|
||||
|
||||
//private void OnCalibPropertyChanged()
|
||||
//{
|
||||
// if (this.InvokeRequired)
|
||||
// {
|
||||
// this.Invoke(new Action(() => OnCalibPropertyChanged()));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// for (int i = 0; i < Config.Results.Count; i++)
|
||||
// {
|
||||
// if (Config.Results[i].Image != null)
|
||||
// {
|
||||
// lvResults.Items[i].BackColor = Color.GreenYellow;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// lvResults.Items[i].BackColor = Color.Transparent;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
Canvas _canvas = new Canvas();
|
||||
private void CtrlCalib9PDynamic_Load(object sender, EventArgs e)
|
||||
{
|
||||
_canvas.IsShowElementList = true;
|
||||
_canvas.Dock = DockStyle.Fill;
|
||||
plImage.Controls.Add(_canvas);
|
||||
|
||||
RemoveHandles();
|
||||
|
||||
if (Camera != null)
|
||||
{
|
||||
Camera.OnImageUpdated -= Camera_UpdateShowImage;
|
||||
Camera.OnImageUpdated += Camera_UpdateShowImage;
|
||||
}
|
||||
|
||||
Config.Results.OnItemChanged = OnResultsListChanged;
|
||||
LoadConfig(Config);
|
||||
}
|
||||
|
||||
private void OnResultsListChanged(NotifyCollectionChangedAction obj)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(new Action(() => FillResults()));
|
||||
}
|
||||
else
|
||||
{
|
||||
FillResults();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveHandles()
|
||||
{
|
||||
if (Camera != null)
|
||||
{
|
||||
Camera.OnImageUpdated -= Camera_UpdateShowImage;
|
||||
}
|
||||
//PubSubCenter.RemoveSubscriber(PubTag.CalibStepDone.ToString(), CalibStepDone);
|
||||
//PubSubCenter.RemoveSubscriber(PubTag.CalibAllDone.ToString(), CalibAllDone);
|
||||
|
||||
chkContinueMode.Checked = false;
|
||||
}
|
||||
|
||||
AutoResetEvent _imageShowedHandle = new AutoResetEvent(false);
|
||||
private void Camera_UpdateShowImage(CameraBase camera, Bitmap image)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(new Action<CameraBase, Bitmap>(Camera_UpdateShowImage), camera, image);
|
||||
}
|
||||
else
|
||||
{
|
||||
_canvas.LoadImage(image);
|
||||
_imageShowedHandle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
//private object CalibAllDone(ISubscriber arg1, object arg2, object arg3)
|
||||
//{
|
||||
// string msg = arg3.ToString();
|
||||
// tsslInfo.Text = msg;
|
||||
|
||||
// return null;
|
||||
//}
|
||||
|
||||
//private object CalibStepDone(ISubscriber arg1, object arg2, object arg3)
|
||||
//{
|
||||
// int index = Convert.ToInt32(arg2);
|
||||
|
||||
// _canvas.LoadImage(Config.Results[index].Image);
|
||||
// _canvas.Elements.Clear();
|
||||
// CrossHair ch = new CrossHair(Config.Results[index].PointResult);
|
||||
// _canvas.Elements.Add(ch);
|
||||
|
||||
// tsslInfo.Text = $"步骤{index + 1}完成";
|
||||
|
||||
// if (chkManualConfirm.Checked)
|
||||
// {
|
||||
// this.Invoke(new Action(() => btnContinueCalib.Visible = true)); ;
|
||||
// _confirmHandle.WaitOne();
|
||||
// }
|
||||
|
||||
// return null;
|
||||
//}
|
||||
|
||||
private void lvConfigs_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (lvResults.SelectedItems.Count <= 0)
|
||||
return;
|
||||
|
||||
var result = lvResults.SelectedItems[0].Tag as CalibrationResult;
|
||||
|
||||
tsslStepHint.Text = $"{(result.StepNum)}/{Config.TotalSteps}";
|
||||
|
||||
if (result.Image != null)
|
||||
{
|
||||
_canvas.LoadImage(result.Image);
|
||||
_canvas.Elements.Clear();
|
||||
_canvas.Elements.Add(new CrossHair(result.PointResult));
|
||||
}
|
||||
}
|
||||
|
||||
private void btnStartCalib_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (OnStartCalibration == null)
|
||||
{
|
||||
throw new ProcessException("StartCalibration不能为空");
|
||||
}
|
||||
|
||||
OnStartCalibration(PLC, Config.TriggerAddress);
|
||||
}
|
||||
|
||||
private void btnStepRun_Click(object sender, EventArgs e)
|
||||
{
|
||||
int stepNum = 1;
|
||||
if (lvResults.SelectedItems.Count > 0)
|
||||
{
|
||||
var step = lvResults.SelectedItems[0].Tag as CalibrationResult;
|
||||
stepNum = step.StepNum;
|
||||
}
|
||||
|
||||
var config = pgCameraConfig.SelectedObject as CameraOprerationConfigBase;
|
||||
|
||||
if (OnCalculateStep == null)
|
||||
{
|
||||
MessageBox.Show("单步运算函数为空");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
CalibrationResult result = OnCalculateStep(Camera, PLC, Config, stepNum);
|
||||
ShowCalibStepDone(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.GetExceptionMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void btnCalcuMatrix_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (OnCalculateAll == null)
|
||||
{
|
||||
MessageBox.Show("标定结果运算函数为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string result = OnCalculateAll(Camera, Config);
|
||||
ShowCalibAllDone(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.GetExceptionMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void btnSnap_Click(object sender, EventArgs e)
|
||||
{
|
||||
CameraOprerationConfigBase config = pgCameraConfig.SelectedObject as CameraOprerationConfigBase;
|
||||
Camera.UploadOperationConfig(config);
|
||||
Camera.Snapshot(config, out HObject hImage);
|
||||
hImage.Dispose();
|
||||
}
|
||||
|
||||
private bool _isContinueMode = false;
|
||||
CameraOprerationConfigBase _selectedCameraOpConfig = null;
|
||||
private void chkContinueMode_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
_selectedCameraOpConfig = pgCameraConfig.SelectedObject as CameraOprerationConfigBase;
|
||||
_isContinueMode = chkContinueMode.Checked;
|
||||
|
||||
if (_isContinueMode)
|
||||
{
|
||||
bool temp = _selectedCameraOpConfig.IsSaveOriginImage;
|
||||
_selectedCameraOpConfig.IsSaveOriginImage = false;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (_isContinueMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
Camera.UploadOperationConfig(_selectedCameraOpConfig);
|
||||
Camera.Snapshot();
|
||||
|
||||
_imageShowedHandle.WaitOne(3000);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
_selectedCameraOpConfig.IsSaveOriginImage = temp;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void btnContinueCalib_Click(object sender, EventArgs e)
|
||||
{
|
||||
_confirmHandle.Set();
|
||||
btnContinueCalib.Visible = false;
|
||||
}
|
||||
|
||||
private void CalibrationDynamic9PointFrm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
RemoveHandles();
|
||||
}
|
||||
|
||||
#region 匿名委托
|
||||
//public virtual void StartCalibration()
|
||||
//{
|
||||
//}
|
||||
|
||||
//public virtual void CalibMarkPoint(CameraBase camera, CalibrationDynamic9PointConfig config, int stepIndex)
|
||||
//{
|
||||
//}
|
||||
|
||||
//public virtual void CalculationMatrix(List<CalibrationDynamic9PointConfig> configs)
|
||||
//{
|
||||
//}
|
||||
|
||||
public Action<PLCBase, int> OnStartCalibration { get; set; }
|
||||
public Func<CameraBase, PLCBase, CalibrationDynamic9PointConfig, int, CalibrationResult> OnCalculateStep { get; set; }
|
||||
public Func<CameraBase, CalibrationDynamic9PointConfig, string> OnCalculateAll { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI显示
|
||||
private void ShowCalibStepDone(CalibrationResult result)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(new Action<CalibrationResult>(ShowCalibStepDone), result);
|
||||
}
|
||||
else
|
||||
{
|
||||
//_canvas.LoadImage(result.Image);
|
||||
_canvas.Elements.Clear();
|
||||
CrossHair ch = new CrossHair(result.PointResult);
|
||||
_canvas.Elements.Add(ch);
|
||||
|
||||
tsslInfo.Text = $"步骤{result.StepNum}完成,{result.PointResult.GetDisplayText()}";
|
||||
|
||||
if (chkManualConfirm.Checked)
|
||||
{
|
||||
btnContinueCalib.Visible = true;
|
||||
}
|
||||
|
||||
if (chkManualConfirm.Checked)
|
||||
{
|
||||
_confirmHandle.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowCalibAllDone(string msg)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(new Action<string>(ShowCalibAllDone), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
tsslInfo.Text = msg;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void btnClearResult_Click(object sender, EventArgs e)
|
||||
{
|
||||
Config.Results.ForEach(r =>
|
||||
{
|
||||
r.Image = null;
|
||||
r.PointResult = new CalibrationPoint();
|
||||
r.IsDone = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
<?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>
|
||||
<metadata name="stspStatus.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>37</value>
|
||||
</metadata>
|
||||
</root>
|
@ -0,0 +1,100 @@
|
||||
using Bro.Common.Base;
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.UI;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
|
||||
namespace Bro.Common.Calibration
|
||||
{
|
||||
[Device("CalibrationStatic9Point", "静态9点标定", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class CalibrationStatic9PointConfigCollection : OperationConfigBase
|
||||
{
|
||||
[Category("标定配置")]
|
||||
[Description("标定配置集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<CalibrationStatic9PointConfig>), typeof(UITypeEditor))]
|
||||
public List<CalibrationStatic9PointConfig> Configs { get; set; } = new List<CalibrationStatic9PointConfig>();
|
||||
}
|
||||
|
||||
public class CalibrationStatic9PointConfig : OperationConfigBase, IComplexDisplay
|
||||
{
|
||||
[Category("相机配置")]
|
||||
[Description("是否相机实时取图")]
|
||||
public bool IsUseRealTimeImage { get; set; } = true;
|
||||
|
||||
[Category("相机配置")]
|
||||
[Description("相机操作配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public CameraOprerationConfigBase CameraOpConfig { get; set; } = new CameraOprerationConfigBase();
|
||||
|
||||
[Category("标定配置")]
|
||||
[Description("XY坐标是否颠倒")]
|
||||
public bool IsInvert { get; set; } = false;
|
||||
|
||||
[Category("标定配置")]
|
||||
[Description("标定X方向间隔")]
|
||||
public int IntervalX { get; set; }
|
||||
|
||||
[Category("标定配置")]
|
||||
[Description("标定Y方向间隔")]
|
||||
public int IntervalY { get; set; }
|
||||
|
||||
[Category("标定配置")]
|
||||
[Description("可忽略的像素差值,取像点的坐标差值必须大于该值才被采用")]
|
||||
public int IgnorePixel { get; set; } = 20;
|
||||
|
||||
[Category("ROI配置")]
|
||||
[Description("标定点的ROI范围集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<ROI_Circle>), typeof(UITypeEditor))]
|
||||
public List<ROI_Circle> ROIList { get; set; } = new List<ROI_Circle>();
|
||||
|
||||
[Category("ROI配置")]
|
||||
[Description("ROI默认半径")]
|
||||
public float ROI_Radius { get; set; } = 50.0f;
|
||||
|
||||
[Category("ROI配置")]
|
||||
[Description("是否启动ROI过滤")]
|
||||
public bool IsEnableROIFilter { get; set; } = true;
|
||||
|
||||
[Category("UI显示配置")]
|
||||
[Description("是否显示备注说明")]
|
||||
public bool IsShowRemark { get; set; } = true;
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return JsonConvert.SerializeObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class PLCSetting : IComplexDisplay
|
||||
{
|
||||
[Category("地址设置")]
|
||||
[Description("X坐标PLC读取地址,例如5012")]
|
||||
public int XAddress { get; set; }
|
||||
|
||||
[Category("地址设置")]
|
||||
[Description("Y坐标PLC读取地址,例如5012")]
|
||||
public int YAddress { get; set; }
|
||||
|
||||
[Category("地址设置")]
|
||||
[Description("是否实时读取PLC地址")]
|
||||
public bool IsRealTimeDataFromPLC { get; set; } = true;
|
||||
|
||||
[Category("运动设置")]
|
||||
[Description("运动坐标X")]
|
||||
public int LocationX { get; set; }
|
||||
|
||||
[Category("运动设置")]
|
||||
[Description("运动坐标Y")]
|
||||
public int LocationY { get; set; }
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return string.Format("X:{0};Y:{1}", LocationX, LocationY);
|
||||
}
|
||||
}
|
||||
}
|
234
src/BRS.Common.Device/Calibration/CalibrationStatic9PointFrm.Designer.cs
generated
Normal file
234
src/BRS.Common.Device/Calibration/CalibrationStatic9PointFrm.Designer.cs
generated
Normal file
@ -0,0 +1,234 @@
|
||||
namespace Bro.Common.Calibration
|
||||
{
|
||||
partial class CalibrationStatic9PointFrm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnDone = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.btnCalibrate = new System.Windows.Forms.Button();
|
||||
this.txtAlgorithemPath = new System.Windows.Forms.TextBox();
|
||||
this.btnQuickSetXY = new System.Windows.Forms.Button();
|
||||
this.propCalibrationConfig = new System.Windows.Forms.PropertyGrid();
|
||||
this.btnReSnap = new System.Windows.Forms.Button();
|
||||
this.btnTest = new System.Windows.Forms.Button();
|
||||
this.btnReadLocation = new System.Windows.Forms.Button();
|
||||
this.btnReloadAlgorithem = new System.Windows.Forms.Button();
|
||||
this.btnClearROI = new System.Windows.Forms.Button();
|
||||
this.plCanvas = new System.Windows.Forms.Panel();
|
||||
this.chkContinueMode = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnDone
|
||||
//
|
||||
this.btnDone.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnDone.Location = new System.Drawing.Point(700, 458);
|
||||
this.btnDone.Name = "btnDone";
|
||||
this.btnDone.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnDone.TabIndex = 1;
|
||||
this.btnDone.Text = "标定完成";
|
||||
this.btnDone.UseVisualStyleBackColor = true;
|
||||
this.btnDone.Click += new System.EventHandler(this.btnDone_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.Location = new System.Drawing.Point(618, 458);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnCancel.TabIndex = 1;
|
||||
this.btnCancel.Text = "取消配置";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// btnCalibrate
|
||||
//
|
||||
this.btnCalibrate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCalibrate.Location = new System.Drawing.Point(700, 408);
|
||||
this.btnCalibrate.Name = "btnCalibrate";
|
||||
this.btnCalibrate.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnCalibrate.TabIndex = 1;
|
||||
this.btnCalibrate.Text = "运行标定";
|
||||
this.btnCalibrate.UseVisualStyleBackColor = true;
|
||||
this.btnCalibrate.Click += new System.EventHandler(this.btnCalibrate_Click);
|
||||
//
|
||||
// txtAlgorithemPath
|
||||
//
|
||||
this.txtAlgorithemPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txtAlgorithemPath.Location = new System.Drawing.Point(12, 459);
|
||||
this.txtAlgorithemPath.Name = "txtAlgorithemPath";
|
||||
this.txtAlgorithemPath.ReadOnly = true;
|
||||
this.txtAlgorithemPath.Size = new System.Drawing.Size(371, 21);
|
||||
this.txtAlgorithemPath.TabIndex = 2;
|
||||
//
|
||||
// btnQuickSetXY
|
||||
//
|
||||
this.btnQuickSetXY.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnQuickSetXY.Location = new System.Drawing.Point(389, 458);
|
||||
this.btnQuickSetXY.Name = "btnQuickSetXY";
|
||||
this.btnQuickSetXY.Size = new System.Drawing.Size(104, 23);
|
||||
this.btnQuickSetXY.TabIndex = 1;
|
||||
this.btnQuickSetXY.Text = "快捷配置XY坐标";
|
||||
this.btnQuickSetXY.UseVisualStyleBackColor = true;
|
||||
this.btnQuickSetXY.Click += new System.EventHandler(this.btnQuickSetXY_Click);
|
||||
//
|
||||
// propCalibrationConfig
|
||||
//
|
||||
this.propCalibrationConfig.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.propCalibrationConfig.Location = new System.Drawing.Point(499, 12);
|
||||
this.propCalibrationConfig.Name = "propCalibrationConfig";
|
||||
this.propCalibrationConfig.Size = new System.Drawing.Size(277, 390);
|
||||
this.propCalibrationConfig.TabIndex = 3;
|
||||
this.propCalibrationConfig.ToolbarVisible = false;
|
||||
//
|
||||
// btnReSnap
|
||||
//
|
||||
this.btnReSnap.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnReSnap.Location = new System.Drawing.Point(618, 408);
|
||||
this.btnReSnap.Name = "btnReSnap";
|
||||
this.btnReSnap.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnReSnap.TabIndex = 1;
|
||||
this.btnReSnap.Text = "重新拍照";
|
||||
this.btnReSnap.UseVisualStyleBackColor = true;
|
||||
this.btnReSnap.Click += new System.EventHandler(this.btnReSnap_Click);
|
||||
//
|
||||
// btnTest
|
||||
//
|
||||
this.btnTest.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnTest.Location = new System.Drawing.Point(499, 457);
|
||||
this.btnTest.Name = "btnTest";
|
||||
this.btnTest.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnTest.TabIndex = 1;
|
||||
this.btnTest.Text = "test";
|
||||
this.btnTest.UseVisualStyleBackColor = true;
|
||||
this.btnTest.Visible = false;
|
||||
this.btnTest.Click += new System.EventHandler(this.btnTest_Click);
|
||||
//
|
||||
// btnReadLocation
|
||||
//
|
||||
this.btnReadLocation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnReadLocation.Location = new System.Drawing.Point(499, 408);
|
||||
this.btnReadLocation.Name = "btnReadLocation";
|
||||
this.btnReadLocation.Size = new System.Drawing.Size(113, 23);
|
||||
this.btnReadLocation.TabIndex = 1;
|
||||
this.btnReadLocation.Text = "PLC读取坐标";
|
||||
this.btnReadLocation.UseVisualStyleBackColor = true;
|
||||
this.btnReadLocation.Click += new System.EventHandler(this.btnReadLocation_Click);
|
||||
//
|
||||
// btnReloadAlgorithem
|
||||
//
|
||||
this.btnReloadAlgorithem.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnReloadAlgorithem.Location = new System.Drawing.Point(700, 433);
|
||||
this.btnReloadAlgorithem.Name = "btnReloadAlgorithem";
|
||||
this.btnReloadAlgorithem.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnReloadAlgorithem.TabIndex = 1;
|
||||
this.btnReloadAlgorithem.Text = "载入算法";
|
||||
this.btnReloadAlgorithem.UseVisualStyleBackColor = true;
|
||||
this.btnReloadAlgorithem.Click += new System.EventHandler(this.btnReloadAlgorithem_Click);
|
||||
//
|
||||
// btnClearROI
|
||||
//
|
||||
this.btnClearROI.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnClearROI.Location = new System.Drawing.Point(618, 433);
|
||||
this.btnClearROI.Name = "btnClearROI";
|
||||
this.btnClearROI.Size = new System.Drawing.Size(76, 23);
|
||||
this.btnClearROI.TabIndex = 1;
|
||||
this.btnClearROI.Text = "清除ROI";
|
||||
this.btnClearROI.UseVisualStyleBackColor = true;
|
||||
this.btnClearROI.Click += new System.EventHandler(this.btnClearROI_Click);
|
||||
//
|
||||
// plCanvas
|
||||
//
|
||||
this.plCanvas.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.plCanvas.Location = new System.Drawing.Point(12, 12);
|
||||
this.plCanvas.Name = "plCanvas";
|
||||
this.plCanvas.Size = new System.Drawing.Size(481, 441);
|
||||
this.plCanvas.TabIndex = 4;
|
||||
//
|
||||
// chkContinueMode
|
||||
//
|
||||
this.chkContinueMode.AutoSize = true;
|
||||
this.chkContinueMode.Location = new System.Drawing.Point(502, 436);
|
||||
this.chkContinueMode.Name = "chkContinueMode";
|
||||
this.chkContinueMode.Size = new System.Drawing.Size(72, 16);
|
||||
this.chkContinueMode.TabIndex = 5;
|
||||
this.chkContinueMode.Text = "连续模式";
|
||||
this.chkContinueMode.UseVisualStyleBackColor = true;
|
||||
this.chkContinueMode.CheckedChanged += new System.EventHandler(this.chkContinueMode_CheckedChanged);
|
||||
//
|
||||
// CalibrationProcessFrm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(788, 496);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.chkContinueMode);
|
||||
this.Controls.Add(this.plCanvas);
|
||||
this.Controls.Add(this.propCalibrationConfig);
|
||||
this.Controls.Add(this.txtAlgorithemPath);
|
||||
this.Controls.Add(this.btnReloadAlgorithem);
|
||||
this.Controls.Add(this.btnClearROI);
|
||||
this.Controls.Add(this.btnCalibrate);
|
||||
this.Controls.Add(this.btnQuickSetXY);
|
||||
this.Controls.Add(this.btnTest);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnReadLocation);
|
||||
this.Controls.Add(this.btnReSnap);
|
||||
this.Controls.Add(this.btnDone);
|
||||
this.KeyPreview = true;
|
||||
this.Name = "CalibrationProcessFrm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "标定过程界面";
|
||||
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CalibrationProcessFrm_FormClosing);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
//private Common.UI.Canvas canvas1;
|
||||
private System.Windows.Forms.Button btnDone;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.Button btnCalibrate;
|
||||
private System.Windows.Forms.TextBox txtAlgorithemPath;
|
||||
private System.Windows.Forms.Button btnQuickSetXY;
|
||||
private System.Windows.Forms.PropertyGrid propCalibrationConfig;
|
||||
private System.Windows.Forms.Button btnReSnap;
|
||||
private System.Windows.Forms.Button btnTest;
|
||||
private System.Windows.Forms.Button btnReadLocation;
|
||||
private System.Windows.Forms.Button btnReloadAlgorithem;
|
||||
private System.Windows.Forms.Button btnClearROI;
|
||||
private System.Windows.Forms.Panel plCanvas;
|
||||
private System.Windows.Forms.CheckBox chkContinueMode;
|
||||
}
|
||||
}
|
393
src/BRS.Common.Device/Calibration/CalibrationStatic9PointFrm.cs
Normal file
393
src/BRS.Common.Device/Calibration/CalibrationStatic9PointFrm.cs
Normal file
@ -0,0 +1,393 @@
|
||||
using Bro.Common.Base;
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Model;
|
||||
using Bro.Common.UI;
|
||||
using HalconDotNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Bro.Common.Calibration
|
||||
{
|
||||
public partial class CalibrationStatic9PointFrm : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// 标定点位信息
|
||||
/// </summary>
|
||||
public List<CalibrationPoint> CPoints
|
||||
{
|
||||
get
|
||||
{
|
||||
return canvas1.Elements.Where(p => p.IsEnabled && (p is CrossHair)).Select(p => ((CrossHair)p).CenterPoint).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运动点位信息
|
||||
/// </summary>
|
||||
public CustomizedPoint MovingPosition { get; set; } = new CustomizedPoint();
|
||||
|
||||
Canvas canvas1 = new Canvas();
|
||||
|
||||
PLCBase PLC = null;
|
||||
CameraBase Camera = null;
|
||||
Bitmap Image = null;
|
||||
CalibrationStatic9PointConfig Config = null;
|
||||
HDevEngineTool tool = null;
|
||||
|
||||
public CalibrationStatic9PointFrm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
canvas1 = new Canvas();
|
||||
canvas1.Dock = DockStyle.Fill;
|
||||
plCanvas.Controls.Add(canvas1);
|
||||
}
|
||||
|
||||
public CalibrationStatic9PointFrm(string display, CameraBase camera, PLCBase plc, Bitmap image, CalibrationStatic9PointConfig config)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(display))
|
||||
{
|
||||
this.Text = display;
|
||||
}
|
||||
|
||||
Camera = camera;
|
||||
PLC = plc;
|
||||
Image = image;
|
||||
propCalibrationConfig.SelectedObject = Config = config;
|
||||
|
||||
Camera.OnImageUpdated -= Camera_UpdateShowImage;
|
||||
Camera.OnImageUpdated += Camera_UpdateShowImage;
|
||||
|
||||
canvas1.LoadImage(Image);
|
||||
|
||||
LoadHalconTool();
|
||||
}
|
||||
|
||||
AutoResetEvent _imgShowedHandle = new AutoResetEvent(true);
|
||||
private void Camera_UpdateShowImage(CameraBase camera, Bitmap image)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(new Action(() => LoadImage(image)));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadImage(image);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadImage(Bitmap image)
|
||||
{
|
||||
canvas1.LoadImage(image);
|
||||
_imgShowedHandle.Set();
|
||||
}
|
||||
|
||||
private void PointTest()
|
||||
{
|
||||
canvas1.Elements.Clear();
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
PointF p = new PointF();
|
||||
p.X = 300 + i * 100;
|
||||
p.Y = 500 + j * 150;
|
||||
|
||||
CrossHair ch = new CrossHair(new CalibrationPoint(p));
|
||||
|
||||
ch.Index = i * 3 + j + 1;
|
||||
ch.Name = p.X.ToString() + "--" + p.Y.ToString();
|
||||
|
||||
canvas1.Elements.Add(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadHalconTool()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Config.CameraOpConfig.AlgorithemPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
txtAlgorithemPath.Text = Config.CameraOpConfig.AlgorithemPath;
|
||||
|
||||
string directoryPath = Path.GetDirectoryName(Config.CameraOpConfig.AlgorithemPath);
|
||||
string fileName = Path.GetFileNameWithoutExtension(Config.CameraOpConfig.AlgorithemPath);
|
||||
|
||||
tool = new HDevEngineTool(directoryPath);
|
||||
tool.LoadProcedure(fileName);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
}
|
||||
|
||||
private void btnDone_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (CPoints.Count < 9)
|
||||
{
|
||||
if (MessageBox.Show("一般需设置至少9个标定点的信息,是否确认完成", "完成确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
|
||||
return;
|
||||
}
|
||||
|
||||
if (CPoints.Count(p => p.X == 0 && p.Y == 0) > 1)
|
||||
{
|
||||
if (MessageBox.Show("标定点的XY信息未设置完成,是否确认完成", "完成确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
|
||||
return;
|
||||
}
|
||||
|
||||
GetCurrentPosition();
|
||||
|
||||
if (Config.IsEnableROIFilter)
|
||||
{
|
||||
Config.ROIList.Clear();
|
||||
|
||||
CPoints.ForEach(u =>
|
||||
{
|
||||
ROI_Circle circle = new ROI_Circle();
|
||||
if (u.IsBasePoint)
|
||||
{
|
||||
circle.ROI_Index = "1";
|
||||
}
|
||||
|
||||
circle.Center = new CustomizedPoint(u.U, u.V);
|
||||
circle.Radius = Config.ROI_Radius;
|
||||
|
||||
Config.ROIList.Add(circle);
|
||||
});
|
||||
}
|
||||
|
||||
this.DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
public virtual void GetCurrentPosition()
|
||||
{
|
||||
//if (Config.PLCSetting.IsRealTimeDataFromPLC)
|
||||
//{
|
||||
// int x = PLC.Read(Config.PLCSetting.XAddress, 2).ParseUnsignShortListToInt()[0];
|
||||
// int y = PLC.Read(Config.PLCSetting.YAddress, 2).ParseUnsignShortListToInt()[0];
|
||||
|
||||
// MovingPosition = new CustomizedPoint(x, y);
|
||||
|
||||
// Config.PLCSetting.LocationX = x;
|
||||
// Config.PLCSetting.LocationY = y;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// MovingPosition = new CustomizedPoint(Config.PLCSetting.LocationX, Config.PLCSetting.LocationY);
|
||||
//}
|
||||
}
|
||||
|
||||
private void btnCalibrate_Click(object sender, EventArgs e)
|
||||
{
|
||||
DoCalibration();
|
||||
}
|
||||
|
||||
private void DoCalibration()
|
||||
{
|
||||
canvas1.Elements.Clear();
|
||||
|
||||
if (Config.IsEnableROIFilter)
|
||||
{
|
||||
Config.ROIList.ForEach(r =>
|
||||
{
|
||||
canvas1.Elements.Add(r);
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HTuple outputX = new HTuple();
|
||||
HTuple outputY = new HTuple();
|
||||
|
||||
using (HObject hImage = canvas1.MAP.ConvertBitmapToHObject())
|
||||
{
|
||||
tool.InputImageDic.Clear();
|
||||
tool.InputImageDic["INPUT_Image"] = hImage;
|
||||
tool.RunProcedure();
|
||||
|
||||
if (!tool.IsSuccessful)
|
||||
throw new ProcessException($"{Config.CameraOpConfig.AlgorithemPath}算法运行失败");
|
||||
|
||||
outputX = tool.GetResultTuple("OUTPUT_X");
|
||||
outputY = tool.GetResultTuple("OUTPUT_Y");
|
||||
}
|
||||
|
||||
List<CrossHair> chList = new List<CrossHair>();
|
||||
for (int i = 0; i < outputX.DArr.Length; i++)
|
||||
{
|
||||
CalibrationPoint point = new CalibrationPoint(new PointF((float)outputX.DArr[i], (float)outputY.DArr[i]));
|
||||
|
||||
if (Config.IsEnableROIFilter && Config.ROIList.Count > 0)
|
||||
{
|
||||
var roi = Config.ROIList.FirstOrDefault(r => r.IsMouseInSide(new Point((int)point.U, (int)point.V)));
|
||||
if (roi != null)
|
||||
{
|
||||
CrossHair ch = new CrossHair(point);
|
||||
ch.IsShowRemark = Config.IsShowRemark;
|
||||
ch.Index = i + 1;
|
||||
ch.Name = point.U.ToString("f3") + "--" + point.V.ToString("f3");
|
||||
|
||||
if (roi.ROI_Index == "1")
|
||||
{
|
||||
ch.CenterPoint.IsBasePoint = true;
|
||||
}
|
||||
|
||||
chList.Add(ch);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CrossHair ch = new CrossHair(point);
|
||||
ch.IsShowRemark = Config.IsShowRemark;
|
||||
ch.Index = i + 1;
|
||||
ch.Name = point.U.ToString("f3") + "--" + point.V.ToString("f3");
|
||||
chList.Add(ch);
|
||||
}
|
||||
}
|
||||
|
||||
Config.ROIList.ForEach(r =>
|
||||
{
|
||||
canvas1.Elements.Add(r);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.GetExceptionMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void btnQuickSetXY_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MessageBox.Show("快捷设置XY坐标仅适用于标定坐标系和相机坐标系基本平行情况下", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CPoints.Count(p => p.IsBasePoint) > 1)
|
||||
{
|
||||
MessageBox.Show("基准点只能选择一个");
|
||||
return;
|
||||
}
|
||||
|
||||
var basePoint = CPoints.FirstOrDefault(p => p.IsBasePoint);
|
||||
if (basePoint == null)
|
||||
{
|
||||
MessageBox.Show("请选择一个基准点");
|
||||
return;
|
||||
}
|
||||
|
||||
List<float> uList = CPoints.Select(p => Math.Abs(p.U - basePoint.U)).OrderBy(u => u).ToList();
|
||||
List<float> vList = CPoints.Select(p => Math.Abs(p.V - basePoint.V)).OrderBy(u => u).ToList();
|
||||
|
||||
float intervalU = uList.FirstOrDefault(u => u > Config.IgnorePixel);
|
||||
float intervalV = vList.FirstOrDefault(u => u > Config.IgnorePixel);
|
||||
|
||||
CPoints.ForEach(p =>
|
||||
{
|
||||
if (!p.IsBasePoint)
|
||||
{
|
||||
if (Config.IsInvert)
|
||||
{
|
||||
p.X = (int)(Math.Round((p.V - basePoint.V) / intervalV)) * Config.IntervalX + basePoint.X;
|
||||
p.Y = (int)(Math.Round((p.U - basePoint.U) / intervalU)) * Config.IntervalY + basePoint.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.X = (int)(Math.Round((p.U - basePoint.U) / intervalU)) * Config.IntervalX + basePoint.X;
|
||||
p.Y = (int)(Math.Round((p.V - basePoint.V) / intervalV)) * Config.IntervalY + basePoint.Y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Config.IsEnableROIFilter)
|
||||
{
|
||||
var roi1st = Config.ROIList.FirstOrDefault(u => u.IsMouseInSide(new Point((int)p.U, (int)p.V)));
|
||||
|
||||
if (roi1st != null)
|
||||
{
|
||||
roi1st.ROI_Index = "1";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
MessageBox.Show("快捷配置完成!");
|
||||
}
|
||||
|
||||
private void btnReSnap_Click(object sender, EventArgs e)
|
||||
{
|
||||
Camera.Snapshot(Config.CameraOpConfig, out HObject hImage);
|
||||
hImage.Dispose();
|
||||
}
|
||||
|
||||
private void chkContinueMode_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (chkContinueMode.Checked)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (chkContinueMode.Checked)
|
||||
{
|
||||
Camera.Snapshot(Config.CameraOpConfig, out HObject hImage);
|
||||
hImage.Dispose();
|
||||
|
||||
_imgShowedHandle.WaitOne(3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void btnTest_Click(object sender, EventArgs e)
|
||||
{
|
||||
PointTest();
|
||||
}
|
||||
|
||||
private void btnReadLocation_Click(object sender, EventArgs e)
|
||||
{
|
||||
//int x = PLC.Read(Config.PLCSetting.XAddress, 2).ParseUnsignShortListToInt()[0];
|
||||
//int y = PLC.Read(Config.PLCSetting.YAddress, 2).ParseUnsignShortListToInt()[0];
|
||||
|
||||
//string msg = string.Format("X:{0};Y:{1}", x, y);
|
||||
//if (MessageBox.Show(msg + "\r\n是否保存到配置?", "坐标获取", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
||||
//{
|
||||
// Config.PLCSetting.LocationX = x;
|
||||
// Config.PLCSetting.LocationY = y;
|
||||
//}
|
||||
|
||||
GetCurrentPosition();
|
||||
}
|
||||
|
||||
private void btnReloadAlgorithem_Click(object sender, EventArgs e)
|
||||
{
|
||||
LoadHalconTool();
|
||||
|
||||
MessageBox.Show("算法重新载入完成");
|
||||
}
|
||||
|
||||
private void btnClearROI_Click(object sender, EventArgs e)
|
||||
{
|
||||
Config.ROIList.Clear();
|
||||
|
||||
DoCalibration();
|
||||
}
|
||||
|
||||
private void CalibrationProcessFrm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
chkContinueMode.Checked = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
277
src/BRS.Common.Device/DeviceBase/AGVBase.cs
Normal file
277
src/BRS.Common.Device/DeviceBase/AGVBase.cs
Normal file
@ -0,0 +1,277 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Drawing.Design;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class AGVBase : DeviceBase, IMonitor
|
||||
{
|
||||
#region Property & Field
|
||||
public virtual AGVInitialConfigBase IConfig
|
||||
{
|
||||
get
|
||||
{
|
||||
return InitialConfig as AGVInitialConfigBase;
|
||||
}
|
||||
}
|
||||
|
||||
string currentPosition = "";
|
||||
public string CurrentPosition
|
||||
{
|
||||
get => currentPosition;
|
||||
set
|
||||
{
|
||||
if (currentPosition != value)
|
||||
{
|
||||
currentPosition = value;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(currentPosition))
|
||||
{
|
||||
OnAGVPositoinChanged?.Invoke(DateTime.Now, currentPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AGVTaskStatus taskStatus = AGVTaskStatus.None;
|
||||
public AGVTaskStatus TaskStatus
|
||||
{
|
||||
get => taskStatus;
|
||||
set
|
||||
{
|
||||
if (taskStatus != value)
|
||||
{
|
||||
taskStatus = value;
|
||||
|
||||
if (taskStatus != AGVTaskStatus.None)
|
||||
{
|
||||
//if (_isTaskRunning && _taskDoneStates.Contains(taskStatus))
|
||||
//{
|
||||
// _taskDoneHandle.Set();
|
||||
// _isTaskRunning = false;
|
||||
//}
|
||||
|
||||
OnAGVTaskStatusChanged?.Invoke(DateTime.Now, taskStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<AGVTaskStatus> _taskRunningStates = new List<AGVTaskStatus>() { AGVTaskStatus.Running, AGVTaskStatus.Waiting, AGVTaskStatus.Suspended };
|
||||
List<AGVTaskStatus> _taskDoneStates = new List<AGVTaskStatus>() { AGVTaskStatus.Cancelled, AGVTaskStatus.Completed, AGVTaskStatus.Failed };
|
||||
|
||||
float batteryLvl = 0;
|
||||
public float BatteryLvl
|
||||
{
|
||||
get => batteryLvl;
|
||||
set
|
||||
{
|
||||
if (batteryLvl != value)
|
||||
{
|
||||
float pre = batteryLvl;
|
||||
batteryLvl = value;
|
||||
OnAGVBatteryLvlChanged?.Invoke(DateTime.Now, pre, batteryLvl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string LastStation { get; set; }
|
||||
public string Destination { get; set; } = "";
|
||||
public ManualResetEvent BatteryHandle { get; set; } = new ManualResetEvent(false);
|
||||
#endregion
|
||||
|
||||
#region DeviceBase
|
||||
protected override void Init()
|
||||
{
|
||||
BatteryHandle = new ManualResetEvent(false);
|
||||
}
|
||||
protected override void Stop()
|
||||
{
|
||||
BatteryHandle.Set();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
public event Action<DateTime, string> OnAGVPositoinChanged;
|
||||
public event Action<DateTime, AGVTaskStatus> OnAGVTaskStatusChanged;
|
||||
public event Action<DateTime, float, float> OnAGVBatteryLvlChanged;
|
||||
// 2022/08/31 未使用事件,暂时注释掉
|
||||
// public event Action<DateTime, IODefinition> OnAGVIOChanged;
|
||||
|
||||
public Action<DateTime, string, IDevice, IMonitorSet> OnMonitorInvoke { get; set; }
|
||||
public Action<DateTime, IDevice, IWarningSet> OnMonitorAlarm { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Method
|
||||
public abstract void TaskOrder(string dest, bool isWaitFinished);
|
||||
public abstract void CancelTask();
|
||||
public abstract void PauseTask();
|
||||
#endregion
|
||||
|
||||
#region IMonitor
|
||||
public abstract void Monitor();
|
||||
public abstract void ResetAlarm();
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Config
|
||||
public class AGVInitialConfigBase : InitialConfigBase, IMonitorConfig, IWarningSetCollection
|
||||
{
|
||||
[Category("监听配置")]
|
||||
[Description("监听间隔,单位ms")]
|
||||
public int ScanInterval { get; set; } = 500;
|
||||
|
||||
//[Category("监听配置")]
|
||||
//[Description("监听的IO信息配置集合")]
|
||||
//[TypeConverter(typeof(CollectionCountConvert))]
|
||||
//[Editor(typeof(ComplexCollectionEditor<IODefinition>), typeof(UITypeEditor))]
|
||||
//public List<IODefinition> IOCollection { get; set; } = new List<IODefinition>();
|
||||
|
||||
//[Category("监听配置")]
|
||||
//[Description("是否采用简单监听模式。true:简单模式,只获取任务状态;false:全部模式,获取任务所有信息")]
|
||||
//public bool IsSimpleMonitor { get; set; } = true;
|
||||
|
||||
private float batteryLvlToCharge = 0.1f;
|
||||
[Category("充电配置")]
|
||||
[Description("充电电池容量,电池容量低于该值时需要充电")]
|
||||
public float BatteryLvlToCharge
|
||||
{
|
||||
get => batteryLvlToCharge;
|
||||
set
|
||||
{
|
||||
if (value >= 1 || value <= 0)
|
||||
{
|
||||
value = 0.1f;
|
||||
}
|
||||
batteryLvlToCharge = value;
|
||||
}
|
||||
}
|
||||
|
||||
private float batteryLvlToCharge_Recommand = 0.3f;
|
||||
[Category("充电配置")]
|
||||
[Description("充电电池容量,电池容量低于该值时,设备空闲时建议充电")]
|
||||
public float BatteryLvlToCharge_Recommand
|
||||
{
|
||||
get => batteryLvlToCharge_Recommand;
|
||||
set
|
||||
{
|
||||
if (value >= 1 || value <= 0)
|
||||
{
|
||||
value = 0.3f;
|
||||
}
|
||||
batteryLvlToCharge_Recommand = value;
|
||||
}
|
||||
}
|
||||
|
||||
private float batteryLvlChargeDone = 0.9f;
|
||||
[Category("充电配置")]
|
||||
[Description("充电完成电池容量,电池容量高于该值时确认充电完成")]
|
||||
public float BatteryLvlChargeDone
|
||||
{
|
||||
get => batteryLvlChargeDone;
|
||||
set
|
||||
{
|
||||
if (value >= 1 || value <= 0)
|
||||
{
|
||||
value = 0.9f;
|
||||
}
|
||||
batteryLvlChargeDone = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("动作设置")]
|
||||
[Description("动作超时设置,单位min")]
|
||||
public float OperationTimeout { get; set; } = 5;
|
||||
|
||||
[Category("警报配置")]
|
||||
[Description("WarningSetCollection:警报配置列表")]
|
||||
[DisplayName("警报配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(WarningSetsEditor<IOWarningSet>), typeof(UITypeEditor))]
|
||||
public List<IWarningSet> WarningSetCollection { get; set; } = new List<IWarningSet>();
|
||||
|
||||
#region IMonitorConfig
|
||||
[Category("监听设置")]
|
||||
[Description("MonitorSetCollection:监听操作配置集合")]
|
||||
[DisplayName("监听配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<IOMonitorSet>), typeof(UITypeEditor))]
|
||||
public List<IMonitorSet> MonitorSetCollection { get; set; } = new List<IMonitorSet>();
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("true:启动监听 false:关闭监听")]
|
||||
[DisplayName("监听启用")]
|
||||
public bool IsEnableMonitor { get; set; } = true;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("扫描间隔时间,单位:ms")]
|
||||
[DisplayName("扫描间隔")]
|
||||
public int MonitorInterval { get; set; } = 500;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("超时设置,单位:ms")]
|
||||
[DisplayName("监听超时")]
|
||||
public int MonitorTimeout { get; set; } = 500;
|
||||
|
||||
public List<IMonitorSet> GetAllMonitorSet()
|
||||
{
|
||||
WarningSetCollection.ForEach(m => m.SourceDevice = this.Name);
|
||||
MonitorSetCollection.ForEach(m => m.SourceDeviceId = this.Id);
|
||||
return MonitorSetCollection;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class AGVOperationConfig : OperationConfigBase
|
||||
{
|
||||
[Category("导航配置")]
|
||||
[Description("AGV行驶目的地")]
|
||||
public string Location { get; set; }
|
||||
|
||||
[Category("导航配置")]
|
||||
[Description("是否等待完成信号")]
|
||||
public bool IsWaitFinished { get; set; } = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public enum AGVCode
|
||||
{
|
||||
QueryPosition = 0x03EC,
|
||||
QueryTaskStatus = 0x03FC,
|
||||
QueryIO = 0x03F5,
|
||||
|
||||
CancelTask = 0x0BBB,
|
||||
PauseTask = 0x0BB9,
|
||||
TaskOrder = 0x0BEB,
|
||||
|
||||
QueryBattery = 0x03EF,
|
||||
}
|
||||
|
||||
public enum AGVTaskStatus
|
||||
{
|
||||
None = 0,
|
||||
Waiting = 1,
|
||||
Running = 2,
|
||||
Suspended = 3,
|
||||
Completed = 4,
|
||||
Failed = 5,
|
||||
Cancelled = 6,
|
||||
}
|
||||
}
|
641
src/BRS.Common.Device/DeviceBase/CameraBase.cs
Normal file
641
src/BRS.Common.Device/DeviceBase/CameraBase.cs
Normal file
@ -0,0 +1,641 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class CameraBase : DeviceBase
|
||||
{
|
||||
private const int IMAGESETLIFETIME = 10;
|
||||
//耗时操作从 _taskFactory分配线程
|
||||
public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
|
||||
public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
|
||||
#region DeviceBase
|
||||
protected override void Start()
|
||||
{
|
||||
//if (clearImageTimer == null)
|
||||
//{
|
||||
// clearImageTimer = new System.Threading.Timer((o) => { ClearImage(); }, null, 0, 1000 * 60 * 120);
|
||||
//}
|
||||
_imageSetList = new ConcurrentDictionary<string, IImageSet>();
|
||||
|
||||
ImageSaveHelper.OnImageSaveExceptionRaised -= ImageSaveHelper_OnImageSaveExceptionRaised;
|
||||
ImageSaveHelper.OnImageSaveExceptionRaised += ImageSaveHelper_OnImageSaveExceptionRaised;
|
||||
base.Start();
|
||||
}
|
||||
|
||||
protected override void Stop()
|
||||
{
|
||||
if (clearImageTimer != null)
|
||||
{
|
||||
clearImageTimer.Change(-1, -1);
|
||||
clearImageTimer.Dispose();
|
||||
clearImageTimer = null;
|
||||
}
|
||||
|
||||
//if (clearImageSetTimer != null)
|
||||
//{
|
||||
// clearImageSetTimer.Change(-1, -1);
|
||||
// clearImageSetTimer.Dispose();
|
||||
// clearImageSetTimer = null;
|
||||
//}
|
||||
}
|
||||
private void ImageSaveHelper_OnImageSaveExceptionRaised(DateTime dt, string msg)
|
||||
{
|
||||
LogAsync(new LogMsg(dt, LogLevel.Error, msg));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 配置相关
|
||||
|
||||
|
||||
public virtual CameraInitialConfigBase IConfig => InitialConfig as CameraInitialConfigBase;
|
||||
|
||||
public abstract IOperationConfig GetOperationConfigFromDevice();
|
||||
|
||||
public abstract void UploadOperationConfig(IOperationConfig config);
|
||||
#endregion
|
||||
|
||||
#region 图片相关
|
||||
public Action<CameraBase, Bitmap, string> OnShowImageUpdated;
|
||||
public async void UpdateImageAsync(Bitmap image, string imgSetId)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
OnShowImageUpdated?.Invoke(this, image, imgSetId);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///图片异步保存
|
||||
/// </summary>
|
||||
public virtual void ImageSaveAsync(string fullName, Bitmap map)
|
||||
{
|
||||
if (!IConfig.ImageSaveOption.IsEnabled)
|
||||
{
|
||||
map?.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
ImageSaveSet imageSaveSet = new ImageSaveSet()
|
||||
{
|
||||
FullName = fullName,
|
||||
SaveImage = map,
|
||||
ImageFormat = IConfig.ImageSaveOption.ImageFormat
|
||||
};
|
||||
|
||||
ImageSaveHelper.ImageSaveAsync(imageSaveSet);
|
||||
}
|
||||
public Action<DateTime, CameraBase, IImageSet> OnImageOutput { get; set; }
|
||||
public event Action OnCameraOpModeChanged;
|
||||
private EnumHelper.CameraOpMode opMode = CameraOpMode.SingleSnapShot;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 运行模式 扫描or拍照
|
||||
/// </summary>
|
||||
public EnumHelper.CameraOpMode OpMode
|
||||
{
|
||||
get => opMode;
|
||||
set
|
||||
{
|
||||
if (opMode != value)
|
||||
{
|
||||
opMode = value;
|
||||
OnCameraOpModeChanged?.BeginInvoke(null, null);
|
||||
CameraOpModeChanged(value);
|
||||
|
||||
if (opMode == CameraOpMode.ContinuousMode)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (CurrentState == DeviceState.DSOpen && opMode == CameraOpMode.ContinuousMode)
|
||||
{
|
||||
Snapshot();
|
||||
ImageShowedHandle.WaitOne();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void CameraOpModeChanged(EnumHelper.CameraOpMode OpMode)
|
||||
{
|
||||
}
|
||||
|
||||
public AutoResetEvent ImageShowedHandle = new AutoResetEvent(false);
|
||||
|
||||
//private Bitmap showImage;
|
||||
/// <summary>
|
||||
/// 输出显示的图片
|
||||
/// </summary>
|
||||
//public virtual Bitmap ShowImage
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return showImage;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// showImage = value;
|
||||
|
||||
// if (showImage != null)
|
||||
// {
|
||||
// OnImageUpdated?.Invoke(this, new Bitmap(showImage));
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// LogAsync(DateTime.Now, $"图片显示异常信息", ex.GetExceptionMessage());
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一次性抓拍
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract void Snapshot();
|
||||
public abstract IImageSet Snapshot(IOperationConfig config);
|
||||
|
||||
public virtual void InitialImageSet(IImageSet set, ImageSaveOption saveOption = null)
|
||||
{
|
||||
if (saveOption != null)
|
||||
{
|
||||
set.ImageSaveOption = saveOption.Copy();
|
||||
}
|
||||
|
||||
//set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage;
|
||||
//set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage;
|
||||
//set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
|
||||
set.CameraId = this.Id;
|
||||
|
||||
set.ImageTime = DateTime.Now;
|
||||
_imageSetList[set.Id] = set;
|
||||
}
|
||||
|
||||
public ImageSet CopyImageSet(ImageSet srcSet)
|
||||
{
|
||||
ImageSet imageSet = new ImageSet
|
||||
{
|
||||
Id = srcSet.Id,
|
||||
//TImage = srcSet.TImage.CopyImage(),
|
||||
BImage = srcSet.BImage.Clone(),
|
||||
ImageSaveOption = srcSet.ImageSaveOption.Copy(),
|
||||
ImageTime = srcSet.ImageTime
|
||||
};
|
||||
return imageSet;
|
||||
}
|
||||
/// <summary>
|
||||
/// 释放图片数据
|
||||
/// </summary>
|
||||
protected virtual void FreeImage()
|
||||
{
|
||||
//if (ShowImage != null)
|
||||
//{
|
||||
// ShowImage.Dispose();
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理硬触发产生的图片缓存 外部业务使用
|
||||
/// </summary>
|
||||
public virtual void RefreshImageBufferHandle()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取图片缓存 外部业务使用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual IImageSet GetImageBuffer(int timeout)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 基元处理
|
||||
public Action<CameraBase, List<IShapeElement>, string> OnElementsUpdated;
|
||||
#endregion
|
||||
|
||||
#region 图片缓存/保存
|
||||
static object _imageSetLock = new object();
|
||||
//cameraBase 内部使用
|
||||
public ConcurrentDictionary<string, IImageSet> _imageSetList = new ConcurrentDictionary<string, IImageSet>();
|
||||
|
||||
//public void NewImageSet(IImageSet set)
|
||||
//{
|
||||
// set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage;
|
||||
// set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage;
|
||||
// set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
|
||||
// set.OnImageSetTimeout += ImageSet_OnImageSetTimeout;
|
||||
|
||||
// set.ImageTime = DateTime.Now;
|
||||
|
||||
// set.CameraId = this.Id;
|
||||
// _imageSetList[set.Id] = set;
|
||||
//}
|
||||
|
||||
//public virtual async void UpdateFitElements(List<IShapeElement> eleList, string imgSetId)
|
||||
//{
|
||||
// await Task.Run(() =>
|
||||
// {
|
||||
// OnElementsUpdated?.BeginInvoke(this, eleList, imgSetId, null, null);
|
||||
// });
|
||||
//}
|
||||
|
||||
public virtual async void DisplayAndSaveOriginImage(string imgSetId)
|
||||
{
|
||||
IImageSet set = _imageSetList.Values.FirstOrDefault(u => u.Id == imgSetId);
|
||||
|
||||
if (set != null && set.BImage != null)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var showImage = set.BImage.ConvertToBitmap();
|
||||
var saveImage = showImage?.CopyBitmap();
|
||||
OnShowImageUpdated?.Invoke(this, showImage, imgSetId);
|
||||
|
||||
if (set.ImageSaveOption != null && !string.IsNullOrEmpty(set.ImageSaveOption.ImageSaveDirectory))
|
||||
{
|
||||
string fullname = Path.Combine(set.ImageSaveOption.ImageSaveDirectory, DateTime.Now.ToString("yyyyMMdd"), $"Origin_{Name}", $"{Name}_{set.Id}.{set.ImageSaveOption.ImageFormat.ToString().ToLower()}");
|
||||
ImageSaveAsync(fullname, saveImage);
|
||||
}
|
||||
//注释注释
|
||||
//释放 himage
|
||||
// ClearImageSet(set);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected string CheckImageDirectory(string dirPath, string prefix)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(dirPath))
|
||||
{
|
||||
dirPath = Path.Combine("D:/Images", DateTime.Now.ToString("yyyyMMdd"), prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
//subDir = Path.Combine(DateTime.Now.ToString("yyyyMMdd"), subDir);
|
||||
dirPath = Path.Combine(dirPath, prefix);
|
||||
}
|
||||
|
||||
//string imgDir = Path.Combine(IConfig.ImgDirectory, subDir, prefix);
|
||||
string imgDir = Path.Combine(dirPath, DateTime.Now.ToString("yyyyMMdd"));
|
||||
|
||||
DirectoryInfo dir = new DirectoryInfo(imgDir);
|
||||
if (!dir.Exists)
|
||||
{
|
||||
dir.Create();
|
||||
}
|
||||
|
||||
return imgDir;
|
||||
}
|
||||
|
||||
//private Timer clearImageSetTimer = null;
|
||||
/// <summary>
|
||||
/// 内部图片缓存清理 (集合中 非托管对象的释放,需要元素出列后 再释放)
|
||||
/// </summary>
|
||||
/// <param name="set"></param>
|
||||
public void ClearImageSet(IImageSet set)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool flag = false;
|
||||
lock (_imageSetLock)
|
||||
{
|
||||
flag = _imageSetList.TryRemove(set.Id, out set);
|
||||
if (flag)
|
||||
{
|
||||
set.Dispose();
|
||||
}
|
||||
//LogAsync(DateTime.Now, $"{Name}移除图片信息{(flag ? "成功" : "失败")},当前缓存数量:{_imageSetList.Count}", "");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Exception, $"清理图片缓存异常,当前缓存数量{_imageSetList.Count},{ex.GetExceptionMessage()}");
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearImageSet(string imgSetId)
|
||||
{
|
||||
//IImageSet set = _imageSetList.Values.First(u => u.Id == imgSetId);
|
||||
//if (set != null)
|
||||
//ClearImageSet(set);
|
||||
}
|
||||
|
||||
private void ImageSet_OnImageSetTimeout(IImageSet set)
|
||||
{
|
||||
//ClearImageSet(set);
|
||||
}
|
||||
|
||||
//private void ClearImageSetPeriodically()
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// DateTime dt = DateTime.Now;
|
||||
// foreach (ImageSet set in _imageSetList)
|
||||
// {
|
||||
// if ((dt - set.InitialTime).TotalSeconds > IMAGESETLIFETIME)
|
||||
// {
|
||||
// ImageSet temp = set;
|
||||
// _imageSetList.TryTake(out temp);
|
||||
// temp.Dispose();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// LogAsync(DateTime.Now, $"定时清理图片缓存异常,当前缓存数量{_imageSetList.Count}", ex.GetExceptionMessage());
|
||||
// }
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region 定时清理图片
|
||||
static readonly object _clearImageLock = new object();
|
||||
protected void ClearImage()
|
||||
{
|
||||
if (IConfig.SaveImageDayLimit > 0)
|
||||
{
|
||||
lock (_clearImageLock)
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"ClearImage Start");
|
||||
|
||||
try
|
||||
{
|
||||
DirectoryInfo dirImage = new DirectoryInfo(IConfig.ImgDirectory);
|
||||
if (dirImage.Exists)
|
||||
{
|
||||
DateTime dtNow = DateTime.Now;
|
||||
|
||||
var folderList = dirImage.GetDirectories().ToList();
|
||||
|
||||
folderList = folderList.Where(f =>
|
||||
{
|
||||
if (f.Name.Length < 8)
|
||||
return false;
|
||||
|
||||
DateTime dt = DateTime.Now;
|
||||
string name = f.Name.Substring(0, 4) + "/" + f.Name.Substring(4, 2) + "/" + f.Name.Substring(6);
|
||||
return DateTime.TryParse(name, out dt);
|
||||
}).OrderBy(u => u.Name).ToList();
|
||||
|
||||
if (folderList.Count > IConfig.SaveImageDayLimit)
|
||||
{
|
||||
folderList.Take(folderList.Count - IConfig.SaveImageDayLimit).ToList().ForEach(f =>
|
||||
{
|
||||
f.Delete(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Exception, $"ClearImage异常{ex.GetExceptionMessage()}");
|
||||
}
|
||||
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"ClearImage Done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private System.Threading.Timer clearImageTimer = null;
|
||||
#endregion
|
||||
|
||||
#region 图片转换
|
||||
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
|
||||
public static extern void CopyMemory(IntPtr dest, IntPtr src, long count);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Config
|
||||
[Device("Camera", "相机取像配置", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class CameraOprerationConfigBase : OperationConfigBase, INotifyPropertyChanged, IComplexDisplay, IHalconToolPath
|
||||
{
|
||||
private float exposure = 0;
|
||||
/// <summary>
|
||||
/// 曝光
|
||||
/// </summary>
|
||||
[Category("取像配置")]
|
||||
[Description("曝光")]
|
||||
[DisplayName("曝光")]
|
||||
public virtual float Exposure
|
||||
{
|
||||
get => exposure;
|
||||
set
|
||||
{
|
||||
if (exposure != value)
|
||||
{
|
||||
exposure = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Exposure"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增益
|
||||
/// </summary>
|
||||
[Category("取像配置")]
|
||||
[Description("增益")]
|
||||
[DisplayName("增益")]
|
||||
public virtual float Gain { get; set; }
|
||||
|
||||
[Category("取像配置")]
|
||||
[Description("曝光修改后等待时间,单位ms。针对部分场景确保曝光修改及时生效。")]
|
||||
[DisplayName("曝光等待")]
|
||||
public virtual int ExposureWaitTime { get; set; }
|
||||
|
||||
[Category("取像配置")]
|
||||
[Description("拍摄后曝光值。可在一次拍摄后将曝光修改为下次拍摄的曝光值,节约曝光生效时间。")]
|
||||
[DisplayName("拍摄后曝光")]
|
||||
public virtual float ExposureAfterSnap { get; set; }
|
||||
|
||||
[Category("算法配置")]
|
||||
[Description("算法路径")]
|
||||
[DisplayName("算法路径")]
|
||||
[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string AlgorithemPath { get; set; } = "";
|
||||
|
||||
[Category("保存设置")]
|
||||
[Description("图片保存配置")]
|
||||
[DisplayName("图片保存配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public ImageSaveOption ImageSaveOption { get; set; } = new ImageSaveOption();
|
||||
|
||||
[Category("延时配置")]
|
||||
[Description("拍照前延时")]
|
||||
[DisplayName("前延时")]
|
||||
public int DelayBefore { get; set; } = 0;
|
||||
|
||||
[Category("延时配置")]
|
||||
[Description("拍照后延时")]
|
||||
[DisplayName("后延时")]
|
||||
public int DelayAfter { get; set; } = 0;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return $"曝光:{Exposure.ToString("f2")} 算法:{AlgorithemPath}";
|
||||
}
|
||||
|
||||
public List<string> GetHalconToolPathList()
|
||||
{
|
||||
return new List<string>() { AlgorithemPath };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 相机初始化配置
|
||||
/// </summary>
|
||||
public class CameraInitialConfigBase : InitialConfigBase
|
||||
{
|
||||
|
||||
[Category("驱动类型")]
|
||||
[Description("驱动类型")]
|
||||
[DisplayName("驱动类型")]
|
||||
[Browsable(true)]
|
||||
[TypeConverter(typeof(CameraTypeConverter))]
|
||||
public override string DriverType { get; set; }
|
||||
|
||||
[Category("保存设置")]
|
||||
[Description("图片保存目录")]
|
||||
[DisplayName("图片保存目录")]
|
||||
[Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))]
|
||||
public virtual string ImgDirectory { get; set; } = @"../Images";
|
||||
|
||||
|
||||
[Category("保存设置")]
|
||||
[Description("图片保存天数")]
|
||||
[DisplayName("图片保存天数")]
|
||||
public virtual int SaveImageDayLimit { get; set; } = 10;
|
||||
|
||||
|
||||
[Category("保存设置")]
|
||||
[Description("图片保存默认配置,主要用于硬触发等没有明确操作配置说明的图片保存")]
|
||||
[DisplayName("图片保存默认配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public virtual ImageSaveOption ImageSaveOption { get; set; } = new ImageSaveOption();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 在线相机初始化配置基类
|
||||
/// </summary>
|
||||
public class OnlineCameraInitialConfigBase : CameraInitialConfigBase
|
||||
{
|
||||
|
||||
|
||||
[Category("相机设置")]
|
||||
[Description("相机序列号")]
|
||||
[DisplayName("序列号")]
|
||||
public virtual string SerialNum { get; set; }
|
||||
|
||||
|
||||
[Category("相机设置")]
|
||||
[Description("相机IP地址")]
|
||||
[DisplayName("相机IP地址")]
|
||||
public virtual string CameraIP { get; set; }
|
||||
|
||||
|
||||
[Category("相机设置")]
|
||||
[Description("上位机IP地址")]
|
||||
[DisplayName("上位机IP地址")]
|
||||
public virtual string ComputerIP { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
[Category("拍摄设置")]
|
||||
[Description("默认曝光值,相机开启后就设置该曝光值")]
|
||||
[DisplayName("默认曝光值")]
|
||||
public virtual float DefaultExposure { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 离线相机初始化配置
|
||||
/// </summary>
|
||||
public class OfflineCameraInitialConfigBase : CameraInitialConfigBase
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Converter & Editor
|
||||
|
||||
|
||||
public class CameraTypeConverter : DeviceTypeConverter<CameraBase>
|
||||
{
|
||||
}
|
||||
|
||||
public class CameraInitialConfigEditor : DeviceInitialConfigEditor<CameraInitialConfigBase>
|
||||
{
|
||||
}
|
||||
|
||||
public class CameraDeviceConverter : ComboBoxItemTypeConvert
|
||||
{
|
||||
public override Hashtable GetConvertHash(ITypeDescriptorContext context)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
var config = scope.Resolve<IProcessConfig>();
|
||||
|
||||
config.CameraConfigCollection.ForEach(camera =>
|
||||
{
|
||||
table[camera.Id] = camera.Name;
|
||||
});
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 辅助类
|
||||
#endregion
|
||||
}
|
18
src/BRS.Common.Device/DeviceBase/ForceSensorBase.cs
Normal file
18
src/BRS.Common.Device/DeviceBase/ForceSensorBase.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class ForceSensorBase : DeviceBase
|
||||
{
|
||||
public abstract ResponseMessage ReadOnce();
|
||||
|
||||
public abstract ResponseMessage StartReading(bool isStart);
|
||||
|
||||
public abstract ResponseMessage ZeroSet();
|
||||
}
|
||||
}
|
244
src/BRS.Common.Device/DeviceBase/IODeviceBase.cs
Normal file
244
src/BRS.Common.Device/DeviceBase/IODeviceBase.cs
Normal file
@ -0,0 +1,244 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class IODeviceBase : DeviceBase, IMonitor
|
||||
{
|
||||
#region Property & Field
|
||||
public virtual IOInitialConfigBase IConfig
|
||||
{
|
||||
get
|
||||
{
|
||||
return InitialConfig as IOInitialConfigBase;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IO的监听值
|
||||
/// </summary>
|
||||
public List<IOItem> CurrentIOs { get; set; } = new List<IOItem>();
|
||||
#endregion
|
||||
|
||||
#region DeviceBase
|
||||
protected override void Init()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Pause()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Resume()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Monitor();
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Event
|
||||
public Action<DateTime, string, IDevice, IMonitorSet> OnMonitorInvoke { get; set; }
|
||||
public Action<DateTime, IDevice, IWarningSet> OnMonitorAlarm { get; set; }
|
||||
|
||||
public virtual void ExcuteMonitorInvoke(DateTime dateTime, string invokeDevice, IDevice device, IMonitorSet monitorSet)
|
||||
{
|
||||
OnMonitorInvoke?.BeginInvoke(dateTime, invokeDevice, device, monitorSet, OnMethodInvoked, null);
|
||||
}
|
||||
|
||||
public abstract void OnMethodInvoked(IAsyncResult ar);
|
||||
|
||||
public virtual void ExcuteMonitorAlarm(DateTime dateTime, IDevice device, IWarningSet warningSet)
|
||||
{
|
||||
OnMonitorAlarm?.BeginInvoke(dateTime, device, warningSet, null, null);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Method
|
||||
public abstract ResponseMessage WriteOutput(int index, bool isOpen, bool isShortSingal = false, int elaspedTime = 0);
|
||||
public abstract ResponseMessage ReadInput(int index, int length);
|
||||
#endregion
|
||||
|
||||
#region IMonitor
|
||||
public abstract void Monitor();
|
||||
|
||||
public virtual void ResetAlarm()
|
||||
{
|
||||
(InitialConfig as MotionCardInitialConfigBase).WarningSetCollection.ForEach(ws => ws.CurrentStatus = false);
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}重置报警");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Device("IOOperation", "IO操作配置", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class IOOperationConfigBase : OperationConfigBase, IComplexDisplay
|
||||
{
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[DisplayName("1.IO预检查")]
|
||||
[Description("IO预检查定义集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(IOOperationItemCollectionEditor), typeof(UITypeEditor))]
|
||||
public List<IOOperationItem> PreCheckIOCollection { get; set; } = new List<IOOperationItem>();
|
||||
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[Description("超时设置,单位:ms")]
|
||||
[DisplayName("2.IO预检查超时")]
|
||||
public int PreCheckIOTimeout { get; set; } = 0;
|
||||
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[DisplayName("3.IO输出")]
|
||||
[Description("IO输出定义集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(IOOperationItemCollectionEditor), typeof(UITypeEditor))]
|
||||
public List<IOOperationItem> IOOutputCollection { get; set; } = new List<IOOperationItem>();
|
||||
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[DisplayName("4.IO输出确认")]
|
||||
[Description("IO确认定义集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(IOOperationItemCollectionEditor), typeof(UITypeEditor))]
|
||||
public List<IOOperationItem> IOConfirmCollection { get; set; } = new List<IOOperationItem>();
|
||||
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[Description("超时设置,单位:ms")]
|
||||
[DisplayName("5.IO输出确认超时")]
|
||||
public int IOConfirmTimeout { get; set; } = 0;
|
||||
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[Description("IO操作前延时,单位ms")]
|
||||
public virtual int DelayBefore { get; set; } = 0;
|
||||
|
||||
[Category("\t\t\tIO操作配置")]
|
||||
[Description("IO操作后延时,单位ms")]
|
||||
public virtual int DelayAfter { get; set; } = 0;
|
||||
|
||||
public virtual string GetDisplayText()
|
||||
{
|
||||
string preCheck = "";
|
||||
PreCheckIOCollection.ForEach(i =>
|
||||
{
|
||||
preCheck += i.GetDisplayText() + " ";
|
||||
});
|
||||
if (preCheck != "")
|
||||
{
|
||||
preCheck = " 预检:" + preCheck;
|
||||
}
|
||||
|
||||
string output = "";
|
||||
IOOutputCollection.ForEach(i =>
|
||||
{
|
||||
output += i.GetDisplayText() + " ";
|
||||
});
|
||||
if (output != "")
|
||||
{
|
||||
output = " 输出:" + output;
|
||||
}
|
||||
string confirm = "";
|
||||
IOConfirmCollection.ForEach(i =>
|
||||
{
|
||||
confirm += i.GetDisplayText() + " ";
|
||||
});
|
||||
if (confirm != "")
|
||||
{
|
||||
confirm = " 确认:" + confirm;
|
||||
}
|
||||
|
||||
return (preCheck + output + confirm).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public class IOInitialConfigBase : InitialConfigBase, IMonitorConfig, IIOModuleConfig, IWarningSetCollection
|
||||
{
|
||||
[Category("IO设置")]
|
||||
[DisplayName("输出信号时默认持续时间")]
|
||||
[Description("输出信号时默认持续时间,以毫秒为单位")]
|
||||
public int SignalElasped { get; set; } = 100;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("true:监听输出信号 false:不监听输出信号")]
|
||||
[DisplayName("是否监听输出")]
|
||||
public bool IsMonitorOutput { get; set; } = false;
|
||||
|
||||
[Category("IO配置")]
|
||||
[DisplayName("输入IO总数")]
|
||||
[Description("输入IO总数")]
|
||||
public int InputNums { get; set; } = 16;
|
||||
|
||||
[Category("IO配置")]
|
||||
[DisplayName("输出IO总数")]
|
||||
[Description("输出IO总数")]
|
||||
public int OutputNums { get; set; } = 16;
|
||||
|
||||
[Category("IO配置")]
|
||||
[DisplayName("是否输出取反")]
|
||||
[Description("true:输出取反 false:输出不取反")]
|
||||
public bool IsOutputReversed { get; set; } = true;
|
||||
|
||||
[Category("IO配置")]
|
||||
[DisplayName("IO定义集合")]
|
||||
[Description("IO定义集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<IODefinition>), typeof(UITypeEditor))]
|
||||
public List<IODefinition> IODefinitionCollection { get; set; } = new List<IODefinition>();
|
||||
|
||||
[Category("警报配置")]
|
||||
[Description("WarningSetCollection:警报配置列表")]
|
||||
[DisplayName("警报配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(WarningSetsEditor<IOWarningSet>), typeof(UITypeEditor))]
|
||||
public List<IWarningSet> WarningSetCollection { get; set; } = new List<IWarningSet>();
|
||||
|
||||
#region IMonitorConfig
|
||||
[Category("监听设置")]
|
||||
[Description("MonitorSetCollection:监听操作配置集合")]
|
||||
[DisplayName("监听配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<IOMonitorSet>), typeof(UITypeEditor))]
|
||||
public List<IMonitorSet> MonitorSetCollection { get; set; } = new List<IMonitorSet>();
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("true:启动监听 false:关闭监听")]
|
||||
[DisplayName("监听启用")]
|
||||
public bool IsEnableMonitor { get; set; } = true;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("扫描间隔时间,单位:ms")]
|
||||
[DisplayName("扫描间隔")]
|
||||
public int MonitorInterval { get; set; } = 10;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("超时设置,单位:ms")]
|
||||
[DisplayName("监听超时")]
|
||||
public int MonitorTimeout { get; set; } = 500;
|
||||
|
||||
public List<IMonitorSet> GetAllMonitorSet()
|
||||
{
|
||||
WarningSetCollection.ForEach(m => m.SourceDevice = this.Name);
|
||||
MonitorSetCollection.ForEach(m => m.SourceDeviceId = this.Id);
|
||||
return MonitorSetCollection;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
31
src/BRS.Common.Device/DeviceBase/MessageQueueBase.cs
Normal file
31
src/BRS.Common.Device/DeviceBase/MessageQueueBase.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Drawing.Design;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class MessageQueueBase : DeviceBase
|
||||
{
|
||||
public event Action<DateTime, IRemoteMessage> OnRemoteMessageReceived;
|
||||
|
||||
public abstract ResponseMessage SendMsg<T>(T t, bool isSendChannel = true) where T : IRemoteMessage;
|
||||
|
||||
public virtual void RemoteMessageReceived(DateTime dt,IRemoteMessage msg)
|
||||
{
|
||||
OnRemoteMessageReceived?.Invoke(dt, msg);
|
||||
}
|
||||
}
|
||||
}
|
232
src/BRS.Common.Device/DeviceBase/ModbusASCIICommBase.cs
Normal file
232
src/BRS.Common.Device/DeviceBase/ModbusASCIICommBase.cs
Normal file
@ -0,0 +1,232 @@
|
||||
using BRS.Common.Device.Helper;
|
||||
using BRS.Common.Factory;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public class ModbusASCIICommBase : DeviceBase
|
||||
{
|
||||
public SerialPort sp = null;
|
||||
public ModbusASCIIInitialConfigBase IConfig
|
||||
{
|
||||
get => InitialConfig as ModbusASCIIInitialConfigBase;
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
if (sp == null)
|
||||
{
|
||||
sp = new SerialPort(IConfig.Port);
|
||||
sp.BaudRate = int.Parse(IConfig.BaudRate);
|
||||
sp.Parity = IConfig.Parity;
|
||||
sp.DataBits = IConfig.DataBits;
|
||||
sp.StopBits = IConfig.StopBits;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Pause()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Resume()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
if (!SerialPortHelper.StartPort(ref sp, out string errorMsg))
|
||||
{
|
||||
throw new ProcessException($"{Name}{sp.PortName}开启失败,{errorMsg}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Stop()
|
||||
{
|
||||
if (!SerialPortHelper.ClosePort(sp.PortName, out string errorMsg))
|
||||
{
|
||||
throw new ProcessException($"{Name}{sp.PortName}关闭失败,{errorMsg}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写寄存器
|
||||
/// </summary>
|
||||
/// <param name="SlaveAddress"></param>
|
||||
/// <param name="adr"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] WriteSingle(string SlaveAddress, string adr, string data, int start = 1, int len = 0)
|
||||
{
|
||||
byte[] src = new byte[16];
|
||||
//起始值
|
||||
src[0] = 0x3A;
|
||||
//从站地址
|
||||
var nodeBytes = Encoding.ASCII.GetBytes(SlaveAddress);
|
||||
//src[1] = nodeBytes[0];
|
||||
//src[2] = nodeBytes[1];
|
||||
Array.Copy(nodeBytes, 0, src, 1, 2);
|
||||
//功能码
|
||||
src[3] = Encoding.ASCII.GetBytes("0")[0];
|
||||
src[4] = Encoding.ASCII.GetBytes("6")[0];
|
||||
//起始地址
|
||||
var addBytes = Encoding.ASCII.GetBytes(adr);
|
||||
Array.Copy(addBytes, 0, src, 5, 4);
|
||||
//src[5] = addBytes[0];
|
||||
//src[6] = addBytes[1];
|
||||
//src[7] = addBytes[2];
|
||||
//src[8] = addBytes[3];
|
||||
//数据
|
||||
data = data.PadLeft(4, '0');
|
||||
var dataBytes = Encoding.ASCII.GetBytes(data);
|
||||
Array.Copy(dataBytes, 0, src, 9, 4);
|
||||
//src[9] = dataBytes[0];
|
||||
//src[10] = dataBytes[1];
|
||||
//src[11] = dataBytes[2];
|
||||
//src[12] = dataBytes[3];
|
||||
var byt1 = GetLrc(src, start, len).ToString("X2");
|
||||
byte[] byt = Encoding.ASCII.GetBytes(byt1);
|
||||
src[13] = byt[0];
|
||||
src[14] = byt[1];
|
||||
src[15] = 0x0D;
|
||||
src[16] = 0x0A;
|
||||
return src;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写线圈
|
||||
/// </summary>
|
||||
/// <param name="SlaveAddress"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] WriteCoil(string SlaveAddress, string data, int start = 1, int len = 0)
|
||||
{
|
||||
byte[] src = new byte[17];
|
||||
|
||||
//起始值
|
||||
src[0] = 0x3A;
|
||||
|
||||
SlaveAddress = SlaveAddress.PadLeft(2, '0');
|
||||
|
||||
var slave = Encoding.ASCII.GetBytes(SlaveAddress);
|
||||
//从站地址
|
||||
Array.Copy(slave, 0, src, 1, 2);
|
||||
|
||||
string temp = "050000";
|
||||
var tempArr = Encoding.ASCII.GetBytes(temp);
|
||||
Array.Copy(tempArr, 0, src, 3, 6);
|
||||
////功能码
|
||||
//src[3] = Encoding.ASCII.GetBytes("0")[0];
|
||||
//src[4] = Encoding.ASCII.GetBytes("5")[0];
|
||||
|
||||
////起始地址
|
||||
//src[5] = Encoding.ASCII.GetBytes("0")[0];
|
||||
//src[6] = Encoding.ASCII.GetBytes("0")[0];
|
||||
//src[7] = Encoding.ASCII.GetBytes("0")[0];
|
||||
//src[8] = Encoding.ASCII.GetBytes("0")[0];
|
||||
|
||||
//数据
|
||||
data = data.PadLeft(4, '0');
|
||||
var dataArr = Encoding.ASCII.GetBytes(data);
|
||||
Array.Copy(dataArr, 0, src, 9, 4);
|
||||
//src[9] = Encoding.ASCII.GetBytes(data)[0];
|
||||
//src[10] = Encoding.ASCII.GetBytes(data)[1];
|
||||
//src[11] = Encoding.ASCII.GetBytes(data)[2];
|
||||
//src[12] = Encoding.ASCII.GetBytes(data)[3];
|
||||
|
||||
var byt1 = GetLrc(src, start, len).ToString("X2");
|
||||
byte[] byt = Encoding.ASCII.GetBytes(byt1);
|
||||
src[13] = byt[0];
|
||||
src[14] = byt[1];
|
||||
|
||||
src[15] = 0x0D;
|
||||
src[16] = 0x0A;
|
||||
return src;
|
||||
}
|
||||
|
||||
public byte GetLrc(byte[] buffer, int start = 1, int len = 0)
|
||||
{
|
||||
if (buffer == null || buffer.Length == 0) return 0;
|
||||
if (start < 0) return 0;
|
||||
if (len == 0) len = buffer.Length - 2 - 2;
|
||||
int lenght = start + len;
|
||||
if (lenght > buffer.Length) return 0;
|
||||
byte lrc = 0;
|
||||
for (int i = start; i < len; i = i + 2)
|
||||
{
|
||||
var temp = Convert.ToInt32("0x" + System.Text.Encoding.ASCII.GetString(new byte[] { buffer[i], buffer[i + 1] }), 16);
|
||||
lrc += (byte)temp;
|
||||
}
|
||||
lrc = (byte)((lrc ^ 0xFF) + 1);
|
||||
|
||||
return (byte)lrc;
|
||||
}
|
||||
}
|
||||
|
||||
public class ModbusASCIIInitialConfigBase : InitialConfigBase
|
||||
{
|
||||
[Category("通信设置")]
|
||||
[DisplayName("串口号")]
|
||||
[Description("串口号,默认为COM1")]
|
||||
[TypeConverter(typeof(SerialPortConverter))]
|
||||
public string Port { get; set; } = "COM1";
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("波特率")]
|
||||
[TypeConverter(typeof(BaudRateConverter))]
|
||||
public string BaudRate { get; set; } = "9600";
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("奇偶校验位")]
|
||||
public Parity Parity { get; set; } = Parity.None;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("数据位")]
|
||||
public int DataBits { get; set; } = 8;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("停止位")]
|
||||
public StopBits StopBits { get; set; } = StopBits.None;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("读写超时,单位为ms")]
|
||||
public int Timeout { get; set; } = 0;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("读取时等待时间,单位为ms")]
|
||||
public int ReadWaitTime { get; set; } = 10;
|
||||
}
|
||||
|
||||
[Device("ModbusASCIIOperationConfigBase", "ModbusASCII操作配置基类", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class ModbusASCIIOperationConfigBase : OperationConfigBase
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//public class ModbusTypeConverter : StringConverter
|
||||
//{
|
||||
// public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
// {
|
||||
// List<string> devices = DeviceFactory.GetAllSupportDeviceTypeNames(typeof(ModbusASCIICommBase));
|
||||
// devices.Insert(0, "");
|
||||
// return new StandardValuesCollection(devices);
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
619
src/BRS.Common.Device/DeviceBase/MotionCardBase.cs
Normal file
619
src/BRS.Common.Device/DeviceBase/MotionCardBase.cs
Normal file
@ -0,0 +1,619 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Drawing.Design;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
using System.Collections;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class MotionCardBase : DeviceBase, IMonitor, IMotionCard
|
||||
{
|
||||
//耗时操作从 _taskFactory分配线程
|
||||
public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
|
||||
public Action<DateTime, string, IDevice, IMonitorSet> OnMonitorInvoke { get; set; }
|
||||
public Action<DateTime, IDevice, IWarningSet> OnMonitorAlarm { get; set; }
|
||||
//public event Action<int, string> OnAxisAlarmRaised;
|
||||
public Action<int, int, int> OnAxisStatusChanged;
|
||||
public Action<int, int> OnAxisPositionChanged;
|
||||
|
||||
/// <summary>
|
||||
/// int,int 轴号 捕获位置
|
||||
/// </summary>
|
||||
public event Action<int, int> OnCapturePositionChanged;
|
||||
|
||||
public void CapturePositionChanged(int axisIndex, int capturePosition)
|
||||
{
|
||||
OnCapturePositionChanged?.Invoke(axisIndex, capturePosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报警产生 与 取消
|
||||
/// </summary>
|
||||
/// <param name="axisIndex"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAlarm"></param>
|
||||
public void AxisAlarmRaised(int axisIndex, string msg, bool isAlarm)
|
||||
{
|
||||
_axisAlarmRaisedFlag[axisIndex] = isAlarm;
|
||||
IWarningSet ws = new SimpleWarningSet();
|
||||
ws.WarningCode = msg;
|
||||
ws.WarningDescription = msg;
|
||||
ws.TriggerTime = DateTime.Now;
|
||||
ws.SourceDevice = this.Name;
|
||||
ws.CurrentStatus = isAlarm;
|
||||
|
||||
SaveAlarmCSVAsync(ws.TriggerTime, this.Name, ws);
|
||||
OnMonitorAlarm?.BeginInvoke(ws.TriggerTime, this, ws, null, null);
|
||||
}
|
||||
|
||||
public void AxisStatusChanged(int axisIndex, int preStatus, int curStatus)
|
||||
{
|
||||
OnAxisStatusChanged?.BeginInvoke(axisIndex, preStatus, curStatus, null, null);
|
||||
}
|
||||
|
||||
public void AxisPositionChangedAsync(int axisIndex, int currentPosition)
|
||||
{
|
||||
//OnAxisPositionChanged?.BeginInvoke(axisIndex, currentPosition, null, null);
|
||||
OnAxisPositionChanged?.Invoke(axisIndex, currentPosition);
|
||||
}
|
||||
|
||||
protected virtual void OnAxisLimitAlarm(object state)
|
||||
{
|
||||
int axisIndex = Convert.ToInt32(state);
|
||||
|
||||
if (!_axisAlarmRaisedFlag[axisIndex])
|
||||
{
|
||||
var curStatus = GetAxisStatus(axisIndex);
|
||||
var msg = "卡/核:" + IConfig.CardOrCoreNum;
|
||||
if (((curStatus >> 5) & 1) == 1)
|
||||
{
|
||||
msg += $"轴{axisIndex}在 正极限";
|
||||
}
|
||||
if (((curStatus >> 6) & 1) == 1)
|
||||
{
|
||||
msg += $"轴{axisIndex}在 负极限";
|
||||
}
|
||||
AxisAlarmRaised(axisIndex, msg, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
var enabledList = IConfig.AxisSettings.Where(a => a.IsAxisEnabled).ToList();
|
||||
AxisStatusList = enabledList.ConvertAll(a =>
|
||||
{
|
||||
AxisMovingStatus axisSts = new AxisMovingStatus();
|
||||
axisSts.AxisIndex = a.AxisIndex;
|
||||
axisSts.AxisName = a.AxisName;
|
||||
axisSts.IsMonitorStatus = a.IsMonitorStatus;
|
||||
axisSts.IsMonitorPosition = a.IsMonitorPosition;
|
||||
|
||||
return axisSts;
|
||||
});
|
||||
|
||||
_axisAlarmRaisedFlag = enabledList.ToDictionary(a => a.AxisIndex, a => false);
|
||||
_axisLimitTimer = enabledList.ToDictionary(a => a.AxisIndex, a => new System.Threading.Timer(OnAxisLimitAlarm, a.AxisIndex, -1, -1));
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
Monitor();
|
||||
});
|
||||
base.Start();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取规划位置
|
||||
/// </summary>
|
||||
/// <param name="axisNum">Axis number</param>
|
||||
/// <returns></returns>
|
||||
public abstract double GetPrfPosition(int axisNum);
|
||||
/// <summary>
|
||||
/// 获取目前当前位置
|
||||
/// </summary>
|
||||
/// <param name="axisNum">Axis number</param>
|
||||
/// <returns></returns>
|
||||
public abstract double GetCurPosition(int axisNum);
|
||||
|
||||
public abstract List<AxisInfo> GetCurrentAxisInfo(params string[] axisName);
|
||||
public abstract void Monitor();
|
||||
public abstract ResponseMessage MoveToPoint(IOperationConfig opConfig);
|
||||
public virtual void ResetAlarm()
|
||||
{
|
||||
(InitialConfig as MotionCardInitialConfigBase).WarningSetCollection.ForEach(ws => ws.CurrentStatus = false);
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}重置报警");
|
||||
}
|
||||
|
||||
public abstract ResponseMessage Run(IOperationConfig config);
|
||||
|
||||
public override ResponseMessage RunWrap(IOperationConfig opConfig)
|
||||
{
|
||||
return Run(opConfig);
|
||||
}
|
||||
/// <summary>
|
||||
/// 清除状态
|
||||
/// </summary>
|
||||
/// <param name="startAxisIndex">起始轴号</param>
|
||||
/// <param name="count">数量</param>
|
||||
/// <returns></returns>
|
||||
public abstract bool ClearStatus(int startAxisIndex, int count);
|
||||
|
||||
/// <summary>
|
||||
/// 读取轴状态
|
||||
/// </summary>
|
||||
/// <param name="axisNum">轴号</param>
|
||||
/// <returns></returns>
|
||||
public abstract int GetAxisStatus(int axisNum);
|
||||
|
||||
/// <summary>
|
||||
/// 位置清零
|
||||
/// </summary>
|
||||
/// <param name="startAxisIndex">起始轴号</param>
|
||||
/// <param name="count">数量</param>
|
||||
/// <returns></returns>
|
||||
public abstract bool PositionReset(int startAxisIndex, int count);
|
||||
|
||||
public abstract bool AllAxisOn();
|
||||
|
||||
public abstract bool AllAxisOff();
|
||||
|
||||
public abstract Task<bool> AxisOnAsync(int axisNum);
|
||||
|
||||
public abstract Task<bool> AxisOffAsync(int axisNum);
|
||||
|
||||
/// <summary>
|
||||
/// 单个轴 运动(点到点 jog 回零...)
|
||||
/// </summary>
|
||||
/// <param name="optionPara">运动参数对象</param>
|
||||
public abstract Task<bool> SingleAxisMoving(MovingOption optionPara);
|
||||
public abstract bool SmartGoHome(short AxisIndex, GoHomePara goHomePara);
|
||||
public abstract bool SmartGetHomeStatus(short AxisIndex, GoHomeStatus homeStatus);
|
||||
/// <summary>
|
||||
/// 某个轴运动停止
|
||||
/// </summary>
|
||||
/// <param name="axisNum">轴号</param>
|
||||
/// <param name="option">0表示平滑停止,1表示紧急停止</param>
|
||||
/// <returns></returns>
|
||||
public abstract Task<bool> MoveStop(int axisNum, int option);
|
||||
|
||||
public virtual async void ExcuteMonitorInvoke(DateTime dateTime, string invokeDevice, IDevice device, IMonitorSet monitorSet)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
//Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
OnMonitorInvoke?.Invoke(dateTime, invokeDevice, device, monitorSet);
|
||||
//OnMonitorInvoke?.BeginInvoke(dateTime, invokeDevice, device, monitorSet, OnMethodInvoked, null);
|
||||
});
|
||||
}
|
||||
|
||||
public abstract void OnMethodInvoked(IAsyncResult ar);
|
||||
|
||||
public virtual void ExcuteMonitorAlarm(DateTime dateTime, IDevice device, IWarningSet warningSet)
|
||||
{
|
||||
OnMonitorAlarm?.BeginInvoke(dateTime, device, warningSet, null, null);
|
||||
}
|
||||
|
||||
public virtual MotionCardInitialConfigBase IConfig
|
||||
{
|
||||
get
|
||||
{
|
||||
return InitialConfig as MotionCardInitialConfigBase;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IO的监听值
|
||||
/// </summary>
|
||||
public List<IOItem> CurrentIOs { get; set; } = new List<IOItem>();
|
||||
|
||||
/// <summary>
|
||||
/// 轴的运动状态值
|
||||
/// </summary>
|
||||
public List<AxisMovingStatus> AxisStatusList { get; set; } = new List<AxisMovingStatus>();
|
||||
|
||||
protected Dictionary<int, bool> _axisAlarmRaisedFlag = new Dictionary<int, bool>();
|
||||
protected Dictionary<int, System.Threading.Timer> _axisLimitTimer = new Dictionary<int, System.Threading.Timer>();
|
||||
|
||||
//public Dictionary<int, AxisMovingStatus> AxisStatusList { get; set; } = new Dictionary<int, AxisMovingStatus>();
|
||||
|
||||
public abstract void WriteOutput(short index, IOValue value);
|
||||
|
||||
/// <summary>
|
||||
/// 从控制卡读输入信号
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="value"></param>
|
||||
public abstract bool GetDi(short index);
|
||||
|
||||
#region ImmediatePause
|
||||
/// <summary>
|
||||
/// 启动立即暂停
|
||||
/// </summary>
|
||||
public abstract void SetImmediatePause();
|
||||
|
||||
/// <summary>
|
||||
/// 恢复立即暂停
|
||||
/// </summary>
|
||||
public abstract void ResetImmediatePause(bool isResumeMoving);
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class MotionCardInitialConfigBase : InitialConfigBase, IMonitorConfig, IIOModuleConfig, IWarningSetCollection
|
||||
{
|
||||
[Category("板卡配置")]
|
||||
[DisplayName("卡号或核心号")]
|
||||
[Description("卡号、核心号")]
|
||||
public virtual int CardOrCoreNum { get; set; } = 0;
|
||||
|
||||
[Category("板卡配置")]
|
||||
[DisplayName("初始配置文件路径")]
|
||||
[Description("InitialConfigFilePath:初始配置文件路径")]
|
||||
[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string InitialConfigFilePath { get; set; }
|
||||
|
||||
[Category("扩展模块设置")]
|
||||
[Description("扩展模块数量,ioModel 编号从 0开始")]
|
||||
[DisplayName("扩展模块数量")]
|
||||
public int IOExtNum { get; set; } = -1;
|
||||
|
||||
[Category("扩展模块设置")]
|
||||
[Description("扩展模块配置文件路径")]
|
||||
[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string IOExtConfigFile { get; set; }
|
||||
|
||||
[Category("轴配置")]
|
||||
[DisplayName("轴数量")]
|
||||
[Description("AxisNum:轴数量")]
|
||||
public int AxisNum { get; set; } = 4;
|
||||
|
||||
[Category("轴配置")]
|
||||
[DisplayName("轴配置信息集合")]
|
||||
[Description("AxisSettings:轴配置信息集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<AxisSetting>), typeof(UITypeEditor))]
|
||||
public List<AxisSetting> AxisSettings { get; set; } = new List<AxisSetting>();
|
||||
|
||||
[Category("轴配置")]
|
||||
[DisplayName("轴速度比率")]
|
||||
[Description("AxisVelocityRatio:轴速度比率")]
|
||||
public double AxisVelocityRatio { get; set; } = 1;
|
||||
|
||||
[Category("警报配置")]
|
||||
[Description("WarningSetCollection:警报配置列表")]
|
||||
[DisplayName("警报配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(WarningSetsEditor<IOWarningSet>), typeof(UITypeEditor))]
|
||||
public List<IWarningSet> WarningSetCollection { get; set; } = new List<IWarningSet>();
|
||||
|
||||
[Category("IO配置")]
|
||||
[Description("输入IO总数")]
|
||||
[DisplayName("输入IO总数")]
|
||||
public int InputNums { get; set; } = 16;
|
||||
|
||||
[Category("IO配置")]
|
||||
[Description("输出IO总数")]
|
||||
[DisplayName("输出IO总数")]
|
||||
public int OutputNums { get; set; } = 16;
|
||||
|
||||
[Category("IO配置")]
|
||||
[Description("IO定义集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<IODefinition>), typeof(UITypeEditor))]
|
||||
public List<IODefinition> IODefinitionCollection { get; set; } = new List<IODefinition>();
|
||||
|
||||
[Category("IO配置")]
|
||||
[DisplayName("是否信号模式")]
|
||||
[Description("true:信号模式,绿色表示有信号,灰色表示无信号 false:电平模式,绿色高电平,灰色低电平,一般情况下低电平表示有信号,板卡默认是电平模式")]
|
||||
public bool IsSignalMode { get; set; } = false;
|
||||
|
||||
#region IMonitorConfig
|
||||
[Category("监听设置")]
|
||||
[Description("MonitorSetCollection:监听操作配置集合")]
|
||||
[DisplayName("监听配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<IOMonitorSet>), typeof(UITypeEditor))]
|
||||
public List<IMonitorSet> MonitorSetCollection { get; set; } = new List<IMonitorSet>();
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("true:启动监听 false:关闭监听")]
|
||||
[DisplayName("监听启用")]
|
||||
public bool IsEnableMonitor { get; set; } = true;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("扫描间隔时间,单位:ms")]
|
||||
[DisplayName("扫描间隔")]
|
||||
public int MonitorInterval { get; set; } = 20;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("超时设置,单位:ms")]
|
||||
[DisplayName("监听超时")]
|
||||
public int MonitorTimeout { get; set; } = 500;
|
||||
|
||||
public List<IMonitorSet> GetAllMonitorSet()
|
||||
{
|
||||
WarningSetCollection.ForEach(m => m.SourceDevice = this.Name);
|
||||
MonitorSetCollection.ForEach(m => m.SourceDeviceId = this.Id);
|
||||
return MonitorSetCollection;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Device("MotionCardBase", "板卡操作配置基类", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class MotionCardOperationConfigBase : OperationConfigBase, IComplexDisplay
|
||||
{
|
||||
[Category("板卡操作")]
|
||||
[Description("板卡操作配置基类集合,依次执行")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(MotionCardOperationSetEditor), typeof(UITypeEditor))]
|
||||
public List<MotionCardOperationSet> OperationCollection { get; set; } = new List<MotionCardOperationSet>();
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
//OperationCollection.ForEach(o =>
|
||||
//{
|
||||
// o.MotionCardId = DeviceId;
|
||||
//});
|
||||
|
||||
return string.Join(" ", OperationCollection.Select(u => u.GetDisplayText()));
|
||||
}
|
||||
}
|
||||
|
||||
public class MotionCardOperationSetEditor : ComplexCollectionEditor<MotionCardOperationSet>
|
||||
{
|
||||
public MotionCardOperationSetEditor(Type type) : base(type) { }
|
||||
|
||||
IOperationConfig opConfig = null;
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
if (context.Instance is IOperationConfig config && value is List<MotionCardOperationSet> setList)
|
||||
{
|
||||
opConfig = config;
|
||||
setList.ForEach(set => set.ExecuteDeviceId = opConfig.ExecuteDeviceId);
|
||||
}
|
||||
|
||||
return base.EditValue(context, provider, value);
|
||||
}
|
||||
|
||||
protected override object CreateInstance(Type itemType)
|
||||
{
|
||||
object obj = base.CreateInstance(itemType);
|
||||
|
||||
if (obj is MotionCardOperationSet set)
|
||||
{
|
||||
set.ExecuteDeviceId = opConfig?.ExecuteDeviceId;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class MotionCardOperationObjectEditor : PropertyObjectEditor
|
||||
{
|
||||
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
|
||||
{
|
||||
return UITypeEditorEditStyle.Modal;
|
||||
}
|
||||
|
||||
IOperationConfig opConfig = null;
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
if (context.Instance is IOperationConfig config && value is MotionCardOperationSet set)
|
||||
{
|
||||
opConfig = config;
|
||||
set.ExecuteDeviceId = opConfig.ExecuteDeviceId;
|
||||
}
|
||||
|
||||
return base.EditValue(context, provider, value);
|
||||
}
|
||||
}
|
||||
|
||||
[Device("MotionOperationSet", "运动操作配置基类", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class MotionCardOperationSet : IOOperationConfigBase
|
||||
{
|
||||
#region Ignore
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public override List<int> InputPara { get; set; } = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// 异常反馈值
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public override int ExceptionValue { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 发生异常时的重新尝试次数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public override int ReTryTimes { get; set; } = 1;
|
||||
#endregion
|
||||
|
||||
[Category("2.板卡运动配置")]
|
||||
[DisplayName("运动配置集合")]
|
||||
[Description("MovingOps:多轴并发,运动配置集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(MovingOpsCollectionEditor), typeof(UITypeEditor))]
|
||||
public List<MovingOption> MovingOps { get; set; } = new List<MovingOption>();
|
||||
|
||||
[Category("5.操作延时")]
|
||||
[DisplayName("操作前延时")]
|
||||
[Description("操作前延时,单位ms")]
|
||||
public override int DelayBefore { get; set; } = 0;
|
||||
|
||||
[Category("5.操作延时")]
|
||||
[DisplayName("操作后延时")]
|
||||
[Description("操作后延时,单位ms")]
|
||||
public override int DelayAfter { get; set; } = 0;
|
||||
|
||||
public override string GetDisplayText()
|
||||
{
|
||||
string preCheck = "";
|
||||
PreCheckIOCollection.ForEach(i =>
|
||||
{
|
||||
preCheck += i.GetDisplayText() + " ";
|
||||
});
|
||||
if (preCheck != "")
|
||||
{
|
||||
preCheck = " 预检:" + preCheck;
|
||||
}
|
||||
|
||||
string output = "";
|
||||
IOOutputCollection.ForEach(i =>
|
||||
{
|
||||
output += i.GetDisplayText() + " ";
|
||||
});
|
||||
if (output != "")
|
||||
{
|
||||
output = " 输出:" + output;
|
||||
}
|
||||
string confirm = "";
|
||||
IOConfirmCollection.ForEach(i =>
|
||||
{
|
||||
confirm += i.GetDisplayText() + " ";
|
||||
});
|
||||
if (confirm != "")
|
||||
{
|
||||
confirm = " 确认:" + confirm;
|
||||
}
|
||||
|
||||
string moving = "";
|
||||
MovingOps.ForEach(i =>
|
||||
{
|
||||
moving += i.GetDisplayText() + " ";
|
||||
});
|
||||
|
||||
if (moving != "")
|
||||
{
|
||||
moving = " 运动:" + moving;
|
||||
}
|
||||
|
||||
return (preCheck + output + confirm + moving).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
[Device("MotionOperation", "运动配置", DeviceAttributeType.OperationConfig)]
|
||||
public class MotionOperationCollection : OperationConfigBase, IComplexDisplay
|
||||
{
|
||||
[Category("运动配置")]
|
||||
[DisplayName("运动配置集合")]
|
||||
[Description("MovingOps:多轴并发,运动配置集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<MovingOption>), typeof(UITypeEditor))]
|
||||
public List<MovingOption> MovingOps { get; set; } = new List<MovingOption>();
|
||||
|
||||
[Category("运动配置")]
|
||||
[Description("多轴并发运动超时设置,单位:s")]
|
||||
[DisplayName("多轴并发运动超时")]
|
||||
public int MovingOpsTimeout { get; set; } = 60;
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return $"{string.Join(" ", MovingOps.Select(u => u.GetDisplayText()))}";
|
||||
}
|
||||
}
|
||||
|
||||
#region Converter & Editor
|
||||
public class AxisSettingConverter : ComboBoxItemTypeConvert
|
||||
{
|
||||
public override Hashtable GetConvertHash(ITypeDescriptorContext context)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
var deviceList = scope.Resolve<List<IDevice>>();
|
||||
if (deviceList != null)
|
||||
{
|
||||
var motionCards = deviceList.ConvertAll(d =>
|
||||
{
|
||||
if (d is MotionCardBase motion)
|
||||
{
|
||||
return motion;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
if (motionCards != null)
|
||||
{
|
||||
motionCards.ForEach(m =>
|
||||
{
|
||||
if (m != null)
|
||||
{
|
||||
m.IConfig.AxisSettings.ForEach(a =>
|
||||
{
|
||||
table[a.AxisIndex] = a.AxisIndex + "|" + a.AxisName;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
public class MovingOpsCollectionEditor : ComplexCollectionEditor<MovingOption>
|
||||
{
|
||||
public MovingOpsCollectionEditor(Type type) : base(type)
|
||||
{
|
||||
}
|
||||
|
||||
MotionCardBase motionCard = null;
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
if (context.Instance is MotionCardOperationSet set)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(set.ExecuteDeviceId))
|
||||
{
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
var deviceList = scope.Resolve<List<IDevice>>();
|
||||
if (deviceList != null)
|
||||
{
|
||||
motionCard = deviceList.FirstOrDefault(u => u.Id == set.ExecuteDeviceId) as MotionCardBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (motionCard != null && value is List<MovingOption> ops)
|
||||
{
|
||||
ops.ForEach(o => o.SetAxisSetting(motionCard.IConfig.AxisSettings));
|
||||
}
|
||||
}
|
||||
|
||||
return base.EditValue(context, provider, value);
|
||||
}
|
||||
|
||||
protected override object SetItems(object editValue, object[] value)
|
||||
{
|
||||
Array.ForEach(value, v =>
|
||||
{
|
||||
if (v is MovingOption op && motionCard != null)
|
||||
{
|
||||
op.SetAxisSetting(motionCard.IConfig.AxisSettings);
|
||||
}
|
||||
});
|
||||
|
||||
return base.SetItems(editValue, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
545
src/BRS.Common.Device/DeviceBase/PLCBase.cs
Normal file
545
src/BRS.Common.Device/DeviceBase/PLCBase.cs
Normal file
@ -0,0 +1,545 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Factory;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Design;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.Design;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class PLCBase : DeviceBase, IMonitor, IMotion
|
||||
{
|
||||
public PLCInitialConfigBase IConfig
|
||||
{
|
||||
get => InitialConfig as PLCInitialConfigBase;
|
||||
}
|
||||
|
||||
public abstract List<int> Read(string startAddress, int length);
|
||||
|
||||
public abstract void ReadItem(PLCItem item);
|
||||
public abstract int ReadInt(string startAddress);
|
||||
public abstract string ReadString(string startAddress, ushort length);
|
||||
public abstract float ReadFloat(string startAddress);
|
||||
|
||||
public abstract void WriteItem(PLCItem item, bool waitForReply = true);
|
||||
|
||||
public abstract void WriteInt(string address, int writeValue, bool waitForReply = true);
|
||||
public abstract void WriteString(string address, string writeValue, bool waitForReply = true);
|
||||
public abstract void WriteFloat(string address, float writeValue, bool waitForReply = true);
|
||||
|
||||
#region IMonitor
|
||||
public Action<DateTime, string, IDevice, IMonitorSet> OnMonitorInvoke { get; set; }
|
||||
public Action<DateTime, IDevice, IWarningSet> OnMonitorAlarm { get; set; }
|
||||
|
||||
public List<int> MonitorValues { get; set; } = new List<int>();
|
||||
|
||||
public abstract List<int> GetMonitorValues(int startAddress, int length);
|
||||
|
||||
public virtual void Monitor()
|
||||
{
|
||||
if (IConfig != null
|
||||
&& IConfig.EventStartAddress > 0
|
||||
&& IConfig.EventLength > 0)
|
||||
{
|
||||
while (CurrentState != DeviceState.DSClose && CurrentState != DeviceState.DSExcept)
|
||||
{
|
||||
if (!IConfig.IsEnableMonitor)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
List<int> newValues = GetMonitorValues(IConfig.EventStartAddress, IConfig.EventLength);
|
||||
|
||||
if (newValues == null || newValues.Count == 0)
|
||||
continue;
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
|
||||
if (MonitorValues.Count == newValues.Count)
|
||||
{
|
||||
var tempNew = new List<int>(newValues);
|
||||
var tempOld = new List<int>(MonitorValues);
|
||||
MonitorCheckAndInvoke(tempNew, tempOld);
|
||||
}
|
||||
MonitorValues = new List<int>(newValues);
|
||||
sw.Stop();
|
||||
|
||||
if (sw.ElapsedMilliseconds > 20)
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Detail, $"{this.Name}轮询时间:{sw.ElapsedMilliseconds}");
|
||||
}
|
||||
|
||||
if (IConfig.MonitorInterval > 0)
|
||||
{
|
||||
Thread.Sleep(IConfig.MonitorInterval);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (CurrentState == DeviceState.DSOpen)
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Exception, $"{this.Name}监听异常,{ex.GetExceptionMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void MonitorCheckAndInvoke(List<int> tempNew, List<int> tempOld)
|
||||
{
|
||||
#region PLC警报信息
|
||||
//PLCIConfig.WarningSetCollection.ForEach(w =>
|
||||
Parallel.ForEach(IConfig.WarningSetCollection, warningSet =>
|
||||
{
|
||||
if (warningSet is PLCWarningSet plcWS)
|
||||
{
|
||||
if (plcWS.WarningIndex_Word < 0 || plcWS.WarningIndex_Word >= tempNew.Count)
|
||||
return;
|
||||
|
||||
if (plcWS.WarningIndex_Bit < 0 || plcWS.WarningIndex_Bit > 16)
|
||||
return;
|
||||
int bitbnum = (tempNew[plcWS.WarningIndex_Word] >> plcWS.WarningIndex_Bit);
|
||||
bool isOn = ((tempNew[plcWS.WarningIndex_Word] >> plcWS.WarningIndex_Bit) & 1) == (plcWS.TriggerValue ? 1 : 0);
|
||||
|
||||
if (plcWS.CurrentStatus != isOn)
|
||||
{
|
||||
plcWS.CurrentStatus = isOn;
|
||||
plcWS.TriggerTime = DateTime.Now;
|
||||
|
||||
SaveAlarmCSVAsync(DateTime.Now, this.Name, plcWS);
|
||||
OnMonitorAlarm?.BeginInvoke(DateTime.Now, this, plcWS, null, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
#endregion
|
||||
|
||||
//PLCIConfig.MonitorSetCollection.ForEach(set =>
|
||||
Parallel.ForEach(IConfig.MonitorSetCollection, set =>
|
||||
{
|
||||
PLCMonitorSet monitorSet = set as PLCMonitorSet;
|
||||
|
||||
//xhm
|
||||
if (monitorSet.TriggerIndex == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//var triggerIndex = monitorSet.TriggerIndex / 2;//原始代码
|
||||
var triggerIndex =( monitorSet.TriggerIndex -1)/ 2;//(读取 32位是 plc 2个地址算作一位)
|
||||
if (triggerIndex < 0 || triggerIndex >= tempNew.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int newValue = tempNew[triggerIndex];
|
||||
int oldValue = newValue;
|
||||
|
||||
if (tempOld.Count == 0)
|
||||
{
|
||||
if (monitorSet.IsOriginOutput)
|
||||
{
|
||||
oldValue = -999;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oldValue = tempOld[triggerIndex];
|
||||
}
|
||||
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
if (monitorSet.TriggerValue == -999 || newValue == monitorSet.TriggerValue)
|
||||
{
|
||||
if (monitorSet.OpConfig == null)
|
||||
{
|
||||
monitorSet.OpConfig = new OperationConfigBase();
|
||||
}
|
||||
|
||||
monitorSet.OpConfig.TriggerValue = newValue;
|
||||
monitorSet.OpConfig.InputPara = monitorSet.InputDataIndex.ConvertAll(index =>
|
||||
{
|
||||
return tempNew[index];
|
||||
}).ToList();
|
||||
|
||||
OnMonitorInvoke?.BeginInvoke(DateTime.Now, monitorSet.ExecuteDevice, this, monitorSet, OnMethodInvoked, monitorSet);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnMethodInvoked(IAsyncResult ar)
|
||||
{
|
||||
PLCMonitorSet monitorSet = ar.AsyncState as PLCMonitorSet;
|
||||
|
||||
ResponseMessage resValues = monitorSet.Response;
|
||||
|
||||
if (resValues.Result == (int)ReturnValue.IGNORE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
if (!string.IsNullOrEmpty(monitorSet.ReplyDataAddress) && resValues.DataList.Count > 0)
|
||||
{
|
||||
PLCItem item = new PLCItem
|
||||
{
|
||||
ItemLength = resValues.DataList.Count,
|
||||
Address = monitorSet.ReplyDataAddress,
|
||||
ItemValues = resValues.DataList
|
||||
};
|
||||
WriteItem(item, false);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(monitorSet.NoticeAddress))
|
||||
{
|
||||
int repeatTime = 5;
|
||||
|
||||
//LogAsync(DateTime.Now, methodCode + "开始反馈", "");
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteInt(monitorSet.NoticeAddress, resValues.Result, false);
|
||||
repeatTime = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
repeatTime--;
|
||||
|
||||
if (repeatTime <= 0)
|
||||
{
|
||||
new ProcessException("PLC反馈写入异常", ex, ExceptionLevel.Warning);
|
||||
}
|
||||
}
|
||||
} while (repeatTime > 0);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
LogAsync(DateTime.Now, LogLevel.Detail, $"{Name}反馈完成,耗时{sw.ElapsedMilliseconds}ms,{resValues.GetDisplayText()}");
|
||||
}
|
||||
|
||||
#region Alarm
|
||||
public virtual void ResetAlarm()
|
||||
{
|
||||
IConfig.WarningSetCollection.ForEach(u => u.CurrentStatus = !u.TriggerValue);
|
||||
}
|
||||
|
||||
object _alarmLock = new object();
|
||||
private async void SaveAlarmCSVAsync(DateTime now, string plcName, PLCWarningSet ws)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
lock (_alarmLock)
|
||||
{
|
||||
DirectoryInfo dir = new DirectoryInfo(this.IConfig.LogPath);
|
||||
if (!dir.Exists)
|
||||
{
|
||||
dir.Create();
|
||||
}
|
||||
|
||||
string path = Path.Combine(IConfig.LogPath, $"Alarm_{Name}_{now.ToString("yyyyMMdd")}.csv");
|
||||
bool fileExist = File.Exists(path);
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(path, true, System.Text.Encoding.UTF8))
|
||||
{
|
||||
if (!fileExist)
|
||||
{
|
||||
writer.WriteLine("Time,Source,AlarmCode,AlarmDescription,AlarmStatus");
|
||||
}
|
||||
|
||||
writer.WriteLine($"{now.ToString("HH:mm:ss.fff")},{plcName},{ws.WarningCode},{ws.WarningDescription},{(ws.CurrentStatus ? "报警" : "停止")}");
|
||||
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
protected override void Pause()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Resume()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Monitor();
|
||||
});
|
||||
base.Start();
|
||||
}
|
||||
|
||||
#region IMotion
|
||||
public List<AxisInfo> GetCurrentAxisInfo(params string[] axisName)
|
||||
{
|
||||
List<PLCMotionDefinition_State> mds = new List<PLCMotionDefinition_State>(IConfig.MotionStateCollection);
|
||||
|
||||
if (axisName.Length > 0)
|
||||
{
|
||||
mds = mds.Where(u => axisName.Contains(u.AxisName)).ToList();
|
||||
}
|
||||
|
||||
var locations = mds.ConvertAll(u =>
|
||||
{
|
||||
AxisInfo axisInfo = new AxisInfo();
|
||||
axisInfo.AxisName = u.AxisName;
|
||||
axisInfo.AxisLocation = MonitorValues.Skip(u.RegisterIndex).Take(2).ToList().ParseUnsignShortListToInt()[0];
|
||||
return axisInfo;
|
||||
}).ToList();
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
public virtual ResponseMessage MoveToPoint(IOperationConfig opConfig)
|
||||
{
|
||||
ResponseMessage msg = new ResponseMessage();
|
||||
msg.Result = -1;
|
||||
msg.Message = "运动方法未实现";
|
||||
|
||||
return msg;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class PLCOperationConfigBase : OperationConfigBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 需要操作的PLC项
|
||||
/// </summary>
|
||||
public List<PLCItem> Items { get; set; } = new List<PLCItem>();
|
||||
}
|
||||
|
||||
public class PLCInitialConfigBase : InitialConfigBase, IMonitorConfig, IWarningSetCollection
|
||||
{
|
||||
[Category("驱动类型")]
|
||||
[Description("驱动类型")]
|
||||
[DisplayName("驱动类型")]
|
||||
[TypeConverter(typeof(DeviceTypeSelectorConverter<PLCBase>))]
|
||||
public override string DriverType { get; set; }
|
||||
|
||||
[Category("警报配置")]
|
||||
[Description("警报配置列表")]
|
||||
[DisplayName("警报配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(WarningSetsEditor<PLCWarningSet>), typeof(UITypeEditor))]
|
||||
public List<IWarningSet> WarningSetCollection { get; set; } = new List<IWarningSet>();
|
||||
|
||||
#region IMonitorConfig
|
||||
[Category("监听设置")]
|
||||
[Description("监听操作配置集合")]
|
||||
[DisplayName("监听配置")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<PLCMonitorSet>), typeof(UITypeEditor))]
|
||||
public List<IMonitorSet> MonitorSetCollection { get; set; } = new List<IMonitorSet>();
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("true:启动监听 false:关闭监听")]
|
||||
[DisplayName("监听启用")]
|
||||
public bool IsEnableMonitor { get; set; } = true;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("扫描间隔时间,单位:ms")]
|
||||
[DisplayName("扫描间隔")]
|
||||
public int MonitorInterval { get; set; } = 100;
|
||||
|
||||
[Category("监听设置")]
|
||||
[Description("超时设置,单位:ms")]
|
||||
[DisplayName("监听超时")]
|
||||
public int MonitorTimeout { get; set; } = 500;
|
||||
|
||||
[Category("事件地址设置")]
|
||||
[Description("事件开始地址,PLC的实际寄存器地址。十进制,不包含功能码。")]
|
||||
[DisplayName("监听开始地址")]
|
||||
public int EventStartAddress { get; set; } = 10;
|
||||
|
||||
[Category("事件地址设置")]
|
||||
[Description("事件地址长度,最大长度240")]
|
||||
[DisplayName("监听长度")]
|
||||
public int EventLength { get; set; } = 120;
|
||||
|
||||
public List<IMonitorSet> GetAllMonitorSet()
|
||||
{
|
||||
WarningSetCollection.ForEach(m => m.SourceDevice = this.Name);
|
||||
MonitorSetCollection.ForEach(m => m.SourceDeviceId = this.Id);
|
||||
return MonitorSetCollection;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMotion Related
|
||||
[Category("运动配置")]
|
||||
[Description("运动轴状态集合")]
|
||||
[DisplayName("运动轴状态集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<PLCMotionDefinition_State>), typeof(UITypeEditor))]
|
||||
public List<PLCMotionDefinition_State> MotionStateCollection { get; set; } = new List<PLCMotionDefinition_State>();
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Converter & Editor
|
||||
//public class PLCTypeConverter : StringConverter
|
||||
//{
|
||||
// public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
// {
|
||||
// List<string> devices = DeviceFactory.GetAllSupportDeviceTypeNames(typeof(PLCBase));
|
||||
// devices.Insert(0, "");
|
||||
|
||||
// return new StandardValuesCollection(devices);
|
||||
// }
|
||||
//}
|
||||
|
||||
public class PLCInitialConfigEditor : UITypeEditor
|
||||
{
|
||||
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
|
||||
{
|
||||
return UITypeEditorEditStyle.Modal;
|
||||
}
|
||||
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
|
||||
|
||||
if (edSvc != null)
|
||||
{
|
||||
Form form = new Form
|
||||
{
|
||||
FormBorderStyle = FormBorderStyle.SizableToolWindow,
|
||||
StartPosition = FormStartPosition.CenterParent,
|
||||
Text = context.PropertyDescriptor.DisplayName + "--" + context.PropertyDescriptor.Description
|
||||
};
|
||||
|
||||
PropertyGrid pg = new PropertyGrid
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
ToolbarVisible = false
|
||||
};
|
||||
|
||||
string driverType = (value as PLCInitialConfigBase).DriverType;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(driverType))
|
||||
{
|
||||
IInitialConfig initial = ConfigFactory.GetInitialConfig(driverType);
|
||||
initial.DataFrom(value);
|
||||
value = initial;
|
||||
}
|
||||
|
||||
pg.SelectedObject = value;
|
||||
|
||||
form.Controls.Add(pg);
|
||||
|
||||
form.ShowDialog();
|
||||
|
||||
value = pg.SelectedObject;
|
||||
return value;
|
||||
}
|
||||
|
||||
return base.EditValue(context, provider, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class PLCDeviceIdConverter : ComboBoxItemTypeConvert
|
||||
{
|
||||
public override Hashtable GetConvertHash(ITypeDescriptorContext context)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
var config = scope.Resolve<IProcessConfig>();
|
||||
|
||||
//config.PLCConfigCollection.ForEach(plc =>
|
||||
//{
|
||||
// table[plc.Id] = plc.Name;
|
||||
//});
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
public class PLCDeviceNameConverter : ComboBoxItemTypeConvert
|
||||
{
|
||||
public override Hashtable GetConvertHash(ITypeDescriptorContext context)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
var config = scope.Resolve<IProcessConfig>();
|
||||
|
||||
//config.PLCConfigCollection.ForEach(plc =>
|
||||
//{
|
||||
// table[plc.Name] = plc.Name;
|
||||
//});
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMotion Related
|
||||
public class PLCMotionDefinition_State : IComplexDisplay
|
||||
{
|
||||
[Category("运动轴信息配置")]
|
||||
[Description("运动轴名称")]
|
||||
public string AxisName { get; set; }
|
||||
|
||||
[Category("运动轴信息配置")]
|
||||
[Description("运动轴位置信息索引,和PLC监听地址配合使用,从0开始,长度默认为2")]
|
||||
public int RegisterIndex { get; set; }
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return $"{AxisName} {RegisterIndex}";
|
||||
}
|
||||
}
|
||||
|
||||
public class PLCMotionDefinition_P2P
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
|
||||
public string VelocityRegister { get; set; }
|
||||
|
||||
public string DestinationRegister { get; set; }
|
||||
|
||||
public string TriggerRegister { get; set; }
|
||||
}
|
||||
|
||||
public class PLCMotionDefinition_Jog
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
public string VelocityRegister { get; set; }
|
||||
public string TriggerRegister { get; set; }
|
||||
}
|
||||
#endregion
|
||||
}
|
57
src/BRS.Common.Device/DeviceBase/RS-232CommBase.cs
Normal file
57
src/BRS.Common.Device/DeviceBase/RS-232CommBase.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using BRS.Common.Factory;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class RS_232CommBase : DeviceBase
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Pause()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Resume()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract bool SetLightDealyTime(int aisle);
|
||||
}
|
||||
|
||||
//public class RS_232TypeConverter : StringConverter
|
||||
//{
|
||||
// public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
// {
|
||||
// List<string> devices = DeviceFactory.GetAllSupportDeviceTypeNames(typeof(ModbusCommBase));
|
||||
// devices.Insert(0, "");
|
||||
// return new StandardValuesCollection(devices);
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
843
src/BRS.Common.Device/DeviceBase/RobotBase.cs
Normal file
843
src/BRS.Common.Device/DeviceBase/RobotBase.cs
Normal file
@ -0,0 +1,843 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Autofac;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Drawing.Design;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public abstract class RobotBase : DeviceBase
|
||||
{
|
||||
|
||||
#region Property & Field
|
||||
|
||||
public virtual RobotInitialConfigBase IConfig
|
||||
{
|
||||
get => InitialConfig as RobotInitialConfigBase;
|
||||
}
|
||||
|
||||
public RobotPoint CurrentPoint { get; set; } = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region DeviceBase
|
||||
|
||||
#endregion
|
||||
|
||||
#region Method
|
||||
public abstract void Move(StrRobotPoint point, int moveType, bool isWaitFinished);
|
||||
public abstract void Load(RobotPoint point, int trayType, float startZHeight, float agvStartZHeight, bool isWaitFinished, bool applyTimeout = true);
|
||||
public abstract void UnLoad(RobotPoint point, int trayType, float startZHeight, float agvStartZHeight, bool isWaitFinished);
|
||||
public abstract StrRobotPoint GetPosition();
|
||||
public abstract ResponseMessage SendMsg<T>(T t, bool isWaitReply = true, bool isMonitorMsg = false) where T : IRobotMsg;
|
||||
|
||||
//伺服下电
|
||||
public abstract void power_off();
|
||||
|
||||
//设置伺服
|
||||
public abstract void set_servo_stat();
|
||||
|
||||
//伺服上电
|
||||
public abstract void servo_on();
|
||||
|
||||
//获取点位
|
||||
public abstract void get_pos();
|
||||
//关节运动
|
||||
public abstract void move_j();
|
||||
//直线运动
|
||||
public abstract void move_l();
|
||||
//圆弧运动
|
||||
public abstract void move_c();
|
||||
//整圆运动
|
||||
public abstract void move_ca();
|
||||
|
||||
//连接状态
|
||||
public abstract void connection_status();
|
||||
|
||||
//当前模式
|
||||
public abstract void get_mode();
|
||||
|
||||
//示教模式
|
||||
public abstract void set_mode();
|
||||
|
||||
//运行模式
|
||||
public abstract void set_run_mode();
|
||||
|
||||
//获取坐标系
|
||||
public abstract void get_coord();
|
||||
|
||||
|
||||
//设置坐标系
|
||||
public abstract void set_coord();
|
||||
|
||||
|
||||
//设置点速度
|
||||
public abstract void set_speed(int spendNum);
|
||||
//获取点速度
|
||||
public abstract int get_speed();
|
||||
//获取运行状态
|
||||
public abstract int get_status();
|
||||
//获取伺服状态
|
||||
|
||||
public abstract void get_servo_state();
|
||||
|
||||
//清除伺服错误
|
||||
public abstract void clear_servo();
|
||||
|
||||
|
||||
//获取IO
|
||||
public abstract void get_IO();
|
||||
|
||||
//设置数字输出
|
||||
|
||||
public abstract void set_dout();
|
||||
|
||||
//开启追加运行模式
|
||||
public abstract void motion_mode_on();
|
||||
|
||||
//关闭追加运行模式
|
||||
public abstract void motion_mode_off();
|
||||
|
||||
//发送追加运行队列
|
||||
public abstract void send_queue();
|
||||
|
||||
//追加运行开始
|
||||
public abstract void continuous_motion_start();
|
||||
|
||||
//追加运行暂停
|
||||
public abstract void continuous_motion_pause();
|
||||
|
||||
|
||||
//追加运行停止
|
||||
public abstract void continuous_motion_stop();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class RobotInitialConfigBase : InitialConfigBase//, IWarningSetCollection
|
||||
{
|
||||
[Category("驱动类型")]
|
||||
[Description("驱动类型")]
|
||||
[DisplayName("驱动类型")]
|
||||
//[TypeConverter(typeof(DeviceTypeConverter<RobotBase>))]
|
||||
[TypeConverter(typeof(DeviceTypeSelectorConverter<RobotBase>))]
|
||||
public override string DriverType { get; set; }
|
||||
|
||||
|
||||
#region 上料关键点位
|
||||
[Category("1.机械臂关键点位")]
|
||||
[Description("机械臂起始位置P0")]
|
||||
[DisplayName("机械臂起始位置P0")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotOriginPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("1号机1号位抓取点位置P101")]
|
||||
[DisplayName("1号机1号位抓取点位置P101")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance1GrabPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("1号机2号位抓取点位置P201")]
|
||||
[DisplayName("1号机2号位抓取点位置P201")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance2GrabPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("2号机1号位抓取点位置P101")]
|
||||
[DisplayName("2号机1号位抓取点位置P101")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance1GrabPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("1号机2号位抓取点位置P201")]
|
||||
[DisplayName("2号机2号位抓取点位置P201")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance2GrabPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("1号机1号位放料位置P102")]
|
||||
[DisplayName("1号机1号位放料位置P102")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance1UpPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("1号机2号位放料位置P202")]
|
||||
[DisplayName("1号机2号位放料位置P202")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance2UpPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("2号机1号位放料位置P102")]
|
||||
[DisplayName("2号机1号位放料位置P102")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance1UpPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("2.机械臂上料关键点位")]
|
||||
[Description("2号机2号位放料位置P202")]
|
||||
[DisplayName("2号机2号位放料位置P202")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance2UpPlacePoint { get; set; } = new RobotPoint();
|
||||
#endregion
|
||||
|
||||
|
||||
#region 上料点组
|
||||
[Category("3.机械臂上料项目")]
|
||||
[Description("1号机1号位上料点组")]
|
||||
[DisplayName("1号机1号位上料点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine1Entrance1UpPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
[Category("3.机械臂上料项目")]
|
||||
[Description("1号机2号位上料点组")]
|
||||
[DisplayName("1号机2号位上料点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine1Entrance2UpPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
[Category("3.机械臂上料项目")]
|
||||
[Description("2号机1号位上料点组")]
|
||||
[DisplayName("2号机1号位上料点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine2Entrance1UpPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
[Category("3.机械臂上料项目")]
|
||||
[Description("2号机2号位上料点组")]
|
||||
[DisplayName("2号机2号位上料点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine2Entrance2UpPoints { get; set; } = new List<RobotPoint>();
|
||||
#endregion
|
||||
|
||||
|
||||
#region 下料关键点位
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机1号位取料(下料)点位置P107")]
|
||||
[DisplayName("1号机1号位取料(下料)点位置P107")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance1TakeTyrePoint { get; set; } = new RobotPoint();
|
||||
|
||||
//P107点位斜向上
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机1号位取料(下料)点位置P107斜上方")]
|
||||
[DisplayName("1号机1号位取料(下料)点位置P107斜上方")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance1TakeTyreTiltUpperPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机2号位取料(下料)点位置P207")]
|
||||
[DisplayName("1号机2号位取料(下料)点位置P207")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance2TakeTyrePoint { get; set; } = new RobotPoint();
|
||||
|
||||
//P207斜上方
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机2号位取料(下料)点位置P207斜上方")]
|
||||
[DisplayName("1号机2号位取料(下料)点位置P207斜上方")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance2TakeTyreTiltUpperPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("2号机1号位取料(下料)点位置P107")]
|
||||
[DisplayName("2号机1号位取料(下料)点位置P107")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance1TakeTyrePoint { get; set; } = new RobotPoint();
|
||||
|
||||
//2号机1号位下料点斜上方
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("2号机1号位取料(下料)点位置P107斜上方")]
|
||||
[DisplayName("2号机1号位取料(下料)点位置P107斜上方")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance1TakeTyreTiltUpperPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机2号位取料(下料)点位置P207")]
|
||||
[DisplayName("2号机2号位取料(下料)点位置P207")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance2TakeTyrePoint { get; set; } = new RobotPoint();
|
||||
|
||||
//2号机1号位下料点斜上方
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("2号机2号位取料(下料)点位置P207斜上方")]
|
||||
[DisplayName("2号机2号位取料(下料)点位置P207斜上方")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance2TakeTyreTiltUpperPoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机1号位放置点位置P108")]
|
||||
[DisplayName("1号机1号位放置点位置P108")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance1DownPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机2号位放置点位置P208")]
|
||||
[DisplayName("1号机2号位放置点位置P208")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine1Entrance2DownPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("2号机1号位放置点位置P108")]
|
||||
[DisplayName("2号机1号位放置点位置P108")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance1DownPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("4.机械臂取料(下料)关键点位")]
|
||||
[Description("1号机2号位放置点位置P208")]
|
||||
[DisplayName("2号机2号位放置点位置P208")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotMachine2Entrance2DownPlacePoint { get; set; } = new RobotPoint();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 下料点组
|
||||
[Category("5.机械臂取料(下料)项目")]
|
||||
[Description("1号机1号位取料(下料)点组")]
|
||||
[DisplayName("1号机1号位取料(下料)点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine1Entrance1DownPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
[Category("5.机械臂取料(下料)项目")]
|
||||
[Description("1号机2号位取料(下料)点组")]
|
||||
[DisplayName("1号机2号位取料(下料)点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine1Entrance2DownPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
[Category("5.机械臂取料(下料)项目")]
|
||||
[Description("2号机1号位取料(下料)点组")]
|
||||
[DisplayName("2号机1号位取料(下料)点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine2Entrance1DownPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
[Category("5.机械臂取料(下料)项目")]
|
||||
[Description("2号机2号位取料(下料)点组")]
|
||||
[DisplayName("2号机2号位取料(下料)点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotMachine2Entrance2DownPoints { get; set; } = new List<RobotPoint>();
|
||||
#endregion
|
||||
|
||||
|
||||
[Category("机械臂上料项目")]
|
||||
[Description("路径上料移动点组")]
|
||||
[DisplayName("路径上料移动点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotUpMovePoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
|
||||
[Category("机械臂上料项目")]
|
||||
[Description("路径上料返回点组")]
|
||||
[DisplayName("路径上料返回点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
//[TypeConverter(typeof(SimpleCollectionConvert<double>))]
|
||||
public List<RobotPoint> RobotUPBackPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
|
||||
[Category("机械臂下料项目")]
|
||||
[Description("路径下料移动点组")]
|
||||
[DisplayName("路径下料移动点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
public List<RobotPoint> RobotDownMovePoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
|
||||
[Category("机械臂下料项目")]
|
||||
[Description("路径下料返回点组")]
|
||||
[DisplayName("路径下料返回点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
//[TypeConverter(typeof(SimpleCollectionConvert<double>))]
|
||||
public List<RobotPoint> RobotDownBackPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
|
||||
[Category("机械臂下料项目")]
|
||||
[Description("路径下料返回f辅助点组")]
|
||||
[DisplayName("路径下料返回f辅助点组")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<RobotPoint>), typeof(UITypeEditor))]
|
||||
//[TypeConverter(typeof(SimpleCollectionConvert<double>))]
|
||||
public List<RobotPoint> ConfigRobotDownBackPoints { get; set; } = new List<RobotPoint>();
|
||||
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("机械臂起始位置")]
|
||||
[DisplayName("机械臂起始位置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint RobotInitPosition { get; set; } = new RobotPoint();
|
||||
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("机械臂运动点X1位")]
|
||||
[DisplayName("机械臂运动点X1位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint X1Point { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("机械臂运动点X2位")]
|
||||
[DisplayName("机械臂运动点X2位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint X2Point { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("轮胎半径")]
|
||||
[DisplayName("轮胎半径")]
|
||||
public string RobotTyReRadius { get; set; }
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("轮胎尺寸")]
|
||||
[DisplayName("轮胎尺寸")]
|
||||
// [TypeConverter(typeof(CollectionCountConvert))]
|
||||
// [Editor(typeof(ComplexCollectionEditor<string>), typeof(UITypeEditor))]
|
||||
//[TypeConverter(typeof(SimpleCollectionConvert<double>))]
|
||||
public string SetWhoolSize { get; set; } = "17";
|
||||
|
||||
[Category("机械臂夹爪项目")]
|
||||
[Description("夹紧点")]
|
||||
[DisplayName("夹紧点")]
|
||||
public string GripperFastenPosition { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂夹爪项目")]
|
||||
[Description("放松点")]
|
||||
[DisplayName("放松点")]
|
||||
public string GripperLoosenPosition { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂夹爪项目")]
|
||||
[Description("全松点")]
|
||||
[DisplayName("全松点")]
|
||||
public string GripperAllLoosenPosition { get; set; } = "40000";
|
||||
|
||||
|
||||
[Category("机械臂夹爪项目")]
|
||||
[Description("全紧点")]
|
||||
[DisplayName("全紧点")]
|
||||
public string GripperAllFastenPosition { get; set; } = "92000";
|
||||
|
||||
#region 12寸轮胎
|
||||
[Category("机械臂项目12寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel12GripperUpFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目12寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel12GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目12寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel12GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目12寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel12GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
#region 13寸轮胎
|
||||
[Category("机械臂项目13寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel13GripperUpFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目13寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel13GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目13寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel13GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目13寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel13GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
#region 14寸轮胎
|
||||
[Category("机械臂项目14寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel14GripperUpFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目14寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel14GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目14寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel14GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目14寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel14GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
#region 15寸轮胎
|
||||
[Category("机械臂项目15寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel15GripperUpFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目15寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel15GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目15寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel15GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目15寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel15GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
#region 16寸轮胎
|
||||
[Category("机械臂项目16寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel16GripperUpFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目16寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel16GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
|
||||
[Category("机械臂项目16寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel16GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目16寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel16GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
#region 17寸轮胎
|
||||
[Category("机械臂项目17寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel17GripperUpFasten { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目17寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel17GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目17寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel17GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目17寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel17GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
#region 18寸轮胎
|
||||
[Category("机械臂项目18寸轮胎")]
|
||||
[Description("上料夹紧点")]
|
||||
[DisplayName("上料夹紧点")]
|
||||
public string Wheel18GripperUpFasten { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目18寸轮胎")]
|
||||
[Description("上料放松点")]
|
||||
[DisplayName("上料放松点")]
|
||||
public string Wheel18GripperUpLoosen { get; set; } = "75000";
|
||||
|
||||
[Category("机械臂项目18寸轮胎")]
|
||||
[Description("下料夹紧点")]
|
||||
[DisplayName("下料夹紧点")]
|
||||
public string Wheel18GripperDownFasten { get; set; } = "40000";
|
||||
|
||||
[Category("机械臂项目18寸轮胎")]
|
||||
[Description("下料放松点")]
|
||||
[DisplayName("下料放松点")]
|
||||
public string Wheel18GripperDownLoosen { get; set; } = "2000";
|
||||
#endregion
|
||||
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("1号硫化机1号位")]
|
||||
[DisplayName("1号硫化机1号位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint X1_1Point { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("1号硫化机2号位")]
|
||||
[DisplayName("1号硫化机2号位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint X1_2Point { get; set; } = new RobotPoint();
|
||||
[Category("机械臂项目")]
|
||||
[Description("2号硫化机1号位")]
|
||||
[DisplayName("2号硫化机1号位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint X2_1Point { get; set; } = new RobotPoint();
|
||||
[Category("机械臂项目")]
|
||||
[Description("2号硫化机2号位")]
|
||||
[DisplayName("2号硫化机2号位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint X2_2Point { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("机械臂项目")]
|
||||
[Description("硫化轮胎取出位置")]
|
||||
[DisplayName("硫化轮胎取出位置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint TakeOutPoint { get; set; } = new RobotPoint();
|
||||
|
||||
|
||||
//[Category("机械臂项目")]
|
||||
//[Description("路径移动")]
|
||||
//[DisplayName("路径移动")]
|
||||
|
||||
//[TypeConverter(typeof(CollectionCountConvert))]
|
||||
//[Editor(typeof(ComplexCollectionEditor<RobotPoints>), typeof(UITypeEditor))]
|
||||
//public List<RobotPoints> RobotMovePoints { get; set; } = new List<RobotPoints>();
|
||||
|
||||
//[Category("机械臂项目")]
|
||||
//[Description("路径返回")]
|
||||
//[DisplayName("路径返回")]
|
||||
|
||||
//[TypeConverter(typeof(CollectionCountConvert))]
|
||||
//[Editor(typeof(ComplexCollectionEditor<RobotPoints>), typeof(UITypeEditor))]
|
||||
//public List<RobotPoints> RobotBackPoints { get; set; } = new List<RobotPoints>();
|
||||
|
||||
//[Category("驱动类型")]
|
||||
//[Description("驱动类型")]
|
||||
//[DisplayName("驱动类型")]
|
||||
//[TypeConverter(typeof(DeviceTypeSelectorConverter<RobotBase>))]
|
||||
//public override string DriverType { get; set; }
|
||||
|
||||
//[Category("机器人设置")]
|
||||
//[Description("机器人通信IP")]
|
||||
//[DisplayName("机器人通信IP")]
|
||||
//public string RobotIP { get; set; } = "0.0.0.0";
|
||||
|
||||
//[Category("机器人设置")]
|
||||
//[Description("机器人通信端口")]
|
||||
//[DisplayName("机器人通信端口")]
|
||||
//public int RobotPort { get; set; }
|
||||
|
||||
//[Category("通信设置")]
|
||||
//[Description("反馈超时设置,单位ms")]
|
||||
//[DisplayName("反馈超时设置,单位ms")]
|
||||
//public int ReplyTimeout { get; set; } = 1000;
|
||||
|
||||
//[Category("通信设置")]
|
||||
//[Description("反馈超时重试次数")]
|
||||
//[DisplayName("反馈超时重试次数")]
|
||||
//public int TimeoutRetryTimes { get; set; } = 5;
|
||||
|
||||
//[Category("通信设置")]
|
||||
//[Description("协议文本结束字符")]
|
||||
//[DisplayName("协议文本结束字符")]
|
||||
//public string EndChar { get; set; } = "#";
|
||||
|
||||
//[Category("通信设置")]
|
||||
//[Description("协议内容分隔字符")]
|
||||
//[DisplayName("协议内容分隔字符")]
|
||||
//public string Seperator { get; set; } = ",";
|
||||
|
||||
//[Category("动作设置")]
|
||||
//[Description("动作超时设置,单位min")]
|
||||
//[DisplayName("动作超时设置,单位min")]
|
||||
//public float OperationTimeout { get; set; } = 1;
|
||||
|
||||
|
||||
//[Category("警报配置")]
|
||||
//[Description("警报配置列表")]
|
||||
//[DisplayName("警报配置")]
|
||||
//[TypeConverter(typeof(CollectionCountConvert))]
|
||||
//[Editor(typeof(WarningSetsEditor<PLCWarningSet>), typeof(UITypeEditor))]
|
||||
//public List<IWarningSet> WarningSetCollection { get; set; } = new List<IWarningSet>();
|
||||
|
||||
}
|
||||
|
||||
public class RobotOperationConfigBase : OperationConfigBase
|
||||
{
|
||||
[Category("动作指令")]
|
||||
[Description("动作指令")]
|
||||
public RobotMsgAction Action { get; set; } = RobotMsgAction.Move;
|
||||
|
||||
[Category("参数")]
|
||||
[Description("参数1")]
|
||||
public int Para1 { get; set; } = 0;
|
||||
|
||||
[Category("参数")]
|
||||
[Description("参数2")]
|
||||
public int Para2 { get; set; } = 0;
|
||||
|
||||
[Category("运动配置")]
|
||||
[Description("机器人运动点位")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public RobotPoint Point { get; set; } = new RobotPoint();
|
||||
|
||||
[Category("操作配置")]
|
||||
[Description("是否等待完成信号")]
|
||||
public bool IsWaitFinished { get; set; } = true;
|
||||
}
|
||||
|
||||
public class RobotPoints : IComplexDisplay
|
||||
{
|
||||
//[Category("运动轴信息配置")]
|
||||
//[Description("运动轴名称")]
|
||||
//public string AxisName { get; set; }
|
||||
|
||||
//[Category("运动轴信息配置")]
|
||||
//[Description("运动轴位置信息索引,和PLC监听地址配合使用,从0开始,长度默认为2")]
|
||||
//public int RegisterIndex { get; set; }
|
||||
|
||||
[Category("机械臂坐标")]
|
||||
[Description("路径移动点x")]
|
||||
[DisplayName("路径移动点x")]
|
||||
public double RobotPointX { get; set; }
|
||||
|
||||
[Category("机械臂坐标")]
|
||||
[Description("路径移动点y")]
|
||||
[DisplayName("路径移动点y")]
|
||||
public double RobotPointY { get; set; }
|
||||
|
||||
[Category("机械臂坐标")]
|
||||
[Description("路径移动点z")]
|
||||
[DisplayName("路径移动点z")]
|
||||
public double RobotPointZ { get; set; }
|
||||
|
||||
[Category("机械臂坐标")]
|
||||
[Description("路径移动点rx")]
|
||||
[DisplayName("路径移动点rx")]
|
||||
public double RobotPointRX { get; set; }
|
||||
|
||||
[Category("机械臂坐标")]
|
||||
[Description("路径移动点ry")]
|
||||
[DisplayName("路径移动点ry")]
|
||||
public double RobotPointRY { get; set; }
|
||||
|
||||
[Category("机械臂坐标")]
|
||||
[Description("路径移动点rz")]
|
||||
[DisplayName("路径移动点rz")]
|
||||
public double RobotPointRZ { get; set; }
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
|
||||
return $"路径移动点组";
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRobotMsg
|
||||
{
|
||||
RobotMsgType Type { get; set; }
|
||||
|
||||
int ID { get; set; }
|
||||
|
||||
RobotMsgAction Action { get; set; }
|
||||
|
||||
byte[] GetMsgBytes(string seperator, string endChar, out string dataStr);
|
||||
}
|
||||
|
||||
public enum RobotMsgType
|
||||
{
|
||||
Send = 1,
|
||||
Rec = 2,
|
||||
}
|
||||
|
||||
//public enum RobotMsgAction
|
||||
//{
|
||||
// Move = 1,
|
||||
// Unload = 2,
|
||||
// Load = 3,
|
||||
// GetPosition = 4,
|
||||
// /// <summary>
|
||||
// /// 指定当前点位为基准点
|
||||
// /// </summary>
|
||||
// BasePoint = 5,
|
||||
// IOSet = 6,
|
||||
// Calibration = 9,
|
||||
// StandardPoint = 10,
|
||||
//}
|
||||
|
||||
public enum RobotMsgAction
|
||||
{
|
||||
Move = 1,
|
||||
Unload = 2,
|
||||
Load = 3,
|
||||
GetPosition = 4,
|
||||
/// <summary>
|
||||
/// 指定当前点位为基准点
|
||||
/// </summary>
|
||||
BasePoint = 5,
|
||||
IOSet = 6,
|
||||
IOQuery = 7,
|
||||
Calibration = 9,
|
||||
StandardPoint = 10,
|
||||
|
||||
SetMinHeight = 12,
|
||||
}
|
||||
}
|
161
src/BRS.Common.Device/DeviceBase/SerialPortBase.cs
Normal file
161
src/BRS.Common.Device/DeviceBase/SerialPortBase.cs
Normal file
@ -0,0 +1,161 @@
|
||||
using BRS.Common.Device.Helper;
|
||||
using BRS.Common.Factory;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public class SerialPortBase : DeviceBase
|
||||
{
|
||||
private object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 串口对象
|
||||
/// </summary>
|
||||
private SerialPort _serialPort = null;
|
||||
|
||||
|
||||
protected SerialPort Port
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return _serialPort;
|
||||
}
|
||||
}
|
||||
|
||||
public SerialPortInitialConfigBase IConfig
|
||||
{
|
||||
get => InitialConfig as SerialPortInitialConfigBase;
|
||||
}
|
||||
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
if (_serialPort == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_serialPort == null)
|
||||
{
|
||||
_serialPort = new SerialPort(IConfig.Port);
|
||||
_serialPort.BaudRate = int.Parse(IConfig.BaudRate);
|
||||
_serialPort.Parity = IConfig.Parity;
|
||||
_serialPort.DataBits = IConfig.DataBits;
|
||||
_serialPort.StopBits = IConfig.StopBits;
|
||||
LogAsync(DateTime.Now, LogLevel.Assist, $"{Name}初始化完成");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected override void Pause()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Resume()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
if (!SerialPortHelper.StartPort(ref _serialPort, out string errorMsg))
|
||||
{
|
||||
throw new ProcessException($"{Name}{_serialPort.PortName}开启失败,{errorMsg}");
|
||||
}
|
||||
LogAsync(DateTime.Now, LogLevel.Assist, $"{Name}[{Port.PortName}]已打开");
|
||||
}
|
||||
|
||||
protected override void Stop()
|
||||
{
|
||||
if (!SerialPortHelper.ClosePort(_serialPort.PortName, out string errorMsg))
|
||||
{
|
||||
throw new ProcessException($"{Name}{_serialPort.PortName}关闭失败,{errorMsg}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return _serialPort.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//protected void Read()
|
||||
//{
|
||||
// SerialPortHelper.ReadExisting(_serialPort);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
public class SerialPortInitialConfigBase : InitialConfigBase
|
||||
{
|
||||
|
||||
|
||||
[Category("通信设置")]
|
||||
[DisplayName("串口号")]
|
||||
[Description("串口号,默认为COM1")]
|
||||
[TypeConverter(typeof(SerialPortConverter))]
|
||||
public string Port { get; set; } = "COM1";
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("波特率")]
|
||||
[DisplayName("波特率")]
|
||||
[TypeConverter(typeof(BaudRateConverter))]
|
||||
public string BaudRate { get; set; } = "9600";
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("奇偶校验位")]
|
||||
[DisplayName("校验位")]
|
||||
public Parity Parity { get; set; } = Parity.None;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("数据位")]
|
||||
[DisplayName("数据位")]
|
||||
public int DataBits { get; set; } = 8;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("停止位")]
|
||||
[DisplayName("停止位")]
|
||||
public StopBits StopBits { get; set; } = StopBits.One;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("读写超时,单位:ms")]
|
||||
[DisplayName("读写超时")]
|
||||
public int Timeout { get; set; } = 0;
|
||||
|
||||
[Category("通信设置")]
|
||||
[Description("读取时等待时间,单位:ms")]
|
||||
[DisplayName("读取时等待时间")]
|
||||
public int ReadWaitTime { get; set; } = 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[Device("SerialPortOperationConfigBase", "串口设备操作配置基类", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class SerialPortOperationConfigBase : OperationConfigBase
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
141
src/BRS.Common.Device/DeviceBase/TcpCommBase.cs
Normal file
141
src/BRS.Common.Device/DeviceBase/TcpCommBase.cs
Normal file
@ -0,0 +1,141 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public class TcpClientWrapInitialConfigBase : InitialConfigBase
|
||||
{
|
||||
[Category("连接配置")]
|
||||
[Description("远程IP地址")]
|
||||
[DisplayName("远程IP")]
|
||||
public string RemoteIP { get; set; }
|
||||
|
||||
[Category("连接配置")]
|
||||
[Description("远程端口")]
|
||||
[DisplayName("远程端口")]
|
||||
public int RemotePort { get; set; }
|
||||
}
|
||||
|
||||
public abstract class TcpClientWrapBase : DeviceBase
|
||||
{
|
||||
public TcpClient Client = null;
|
||||
public NetworkStream Stream = null;
|
||||
|
||||
TcpClientWrapInitialConfigBase IConfig
|
||||
{
|
||||
get => InitialConfig as TcpClientWrapInitialConfigBase;
|
||||
}
|
||||
|
||||
protected override void Resume()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Pause()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(IConfig.RemoteIP) || IConfig.RemotePort == 0)
|
||||
{
|
||||
string errorMsg = $"{Name}客户端未指定远程IP地址或端口";
|
||||
LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, errorMsg);
|
||||
|
||||
throw new ProcessException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
InitialTcpClient(ref Client, ref Stream);
|
||||
}
|
||||
|
||||
protected override void Stop()
|
||||
{
|
||||
Stream?.Close();
|
||||
Client?.Close();
|
||||
Client = null;
|
||||
}
|
||||
|
||||
private void InitialTcpClient(ref TcpClient client, ref NetworkStream stream)
|
||||
{
|
||||
if (client == null || !client.Connected || !client.Client.Connected)
|
||||
{
|
||||
client = new TcpClient();
|
||||
client.NoDelay = true;
|
||||
client.Client.NoDelay = true;
|
||||
client.Client.Blocking = true;
|
||||
|
||||
client.Connect(IPAddress.Parse(IConfig.RemoteIP), IConfig.RemotePort);
|
||||
|
||||
stream = client.GetStream();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Task<ResponseMessage> QueryOnce(string queryMsg, bool isReply = false)
|
||||
{
|
||||
ResponseMessage msg = new ResponseMessage();
|
||||
|
||||
try
|
||||
{
|
||||
InitialTcpClient(ref Client, ref Stream);
|
||||
|
||||
byte[] sendBuff = System.Text.Encoding.ASCII.GetBytes(queryMsg);
|
||||
Stream.Write(sendBuff, 0, sendBuff.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg.Result = -1;
|
||||
msg.Message = ex.Message;
|
||||
}
|
||||
|
||||
if (isReply)
|
||||
{
|
||||
if (msg.Result != 1)
|
||||
{
|
||||
return Task.Run(() => msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
//ResponseMessage readMsg = new ResponseMessage();
|
||||
try
|
||||
{
|
||||
byte[] readBuff = new byte[2048];
|
||||
int readSize = Stream.Read(readBuff, 0, readBuff.Length);
|
||||
if (readSize > 0)
|
||||
{
|
||||
msg.DataObj = System.Text.Encoding.ASCII.GetString(readBuff.Take(readSize).ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Result = -1;
|
||||
msg.Message = "读取长度为0,未能获取读取信息";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg.Result = -1;
|
||||
msg.Message = ex.Message;
|
||||
}
|
||||
|
||||
return msg;
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.Run(() => msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
src/BRS.Common.Device/DeviceBase/UI/CtrlCameraRunBase.Designer.cs
generated
Normal file
54
src/BRS.Common.Device/DeviceBase/UI/CtrlCameraRunBase.Designer.cs
generated
Normal file
@ -0,0 +1,54 @@
|
||||
namespace Bro.Common.Base.UI
|
||||
{
|
||||
partial class CtrlCameraRunBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CtrlCameraRunBase));
|
||||
System.Drawing.Drawing2D.Matrix matrix1 = new System.Drawing.Drawing2D.Matrix();
|
||||
this.cvImage = new Bro.Common.UI.Canvas();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cvImage
|
||||
//
|
||||
this.cvImage.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.cvImage.Font = new System.Drawing.Font("Tahoma", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.World, ((byte)(134)));
|
||||
this.cvImage.ImageFilePath = null;
|
||||
this.cvImage.IsShowElementList = false;
|
||||
this.cvImage.IsShowROITool = false;
|
||||
this.cvImage.Location = new System.Drawing.Point(0, 0);
|
||||
this.cvImage.MAP = ((System.Drawing.Bitmap)(resources.GetObject("cvImage.MAP")));
|
||||
this.cvImage.Matrix = matrix1;
|
||||
this.cvImage.MouseState = Bro.Common.Helper.EnumHelper.MouseState.Normal;
|
||||
this.cvImage.Name = "cvImage";
|
||||
this.cvImage.Size = new System.Drawing.Size(478, 440);
|
||||
this.cvImage.TabIndex = 0;
|
||||
//
|
||||
// CtrlCameraRunBase
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.cvImage);
|
||||
this.Name = "CtrlCameraRunBase";
|
||||
this.Size = new System.Drawing.Size(478, 440);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Common.UI.Canvas cvImage;
|
||||
}
|
||||
}
|
80
src/BRS.Common.Device/DeviceBase/UI/CtrlCameraRunBase.cs
Normal file
80
src/BRS.Common.Device/DeviceBase/UI/CtrlCameraRunBase.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using Bro.Common.Interface;
|
||||
using Bro.Common.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Bro.Common.Base.UI
|
||||
{
|
||||
public partial class CtrlCameraRunBase : UserControl, IRunCtrl
|
||||
{
|
||||
public CtrlCameraRunBase()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public IDevice Device { get; set; }
|
||||
|
||||
protected CameraBase Camera
|
||||
{
|
||||
get => Device as CameraBase;
|
||||
}
|
||||
|
||||
public CtrlCameraRunBase(IDevice device)
|
||||
{
|
||||
InitializeComponent();
|
||||
Device = device;
|
||||
|
||||
Camera.OnImageUpdated += Camera_UpdateShowImage;
|
||||
Camera.OnElementsUpdated += Camera_OnElementsUpdated;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, List<ElementBase>> _eleBufferDict = new Dictionary<string, List<ElementBase>>();
|
||||
private volatile string _setId = "";
|
||||
|
||||
protected virtual void Camera_OnElementsUpdated(CameraBase camera, List<ElementBase> eleList, string setId)
|
||||
{
|
||||
if (cvImage.IsHandleCreated)
|
||||
{
|
||||
if (_setId == setId)
|
||||
{
|
||||
eleList.ForEach(e => cvImage.Elements.Add(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
_eleBufferDict[setId] = eleList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Camera_UpdateShowImage(CameraBase camera, Bitmap image, string setId)
|
||||
{
|
||||
_setId = setId;
|
||||
|
||||
if (cvImage.IsHandleCreated)
|
||||
{
|
||||
cvImage.LoadImage(image);
|
||||
|
||||
if (_eleBufferDict.ContainsKey(setId))
|
||||
{
|
||||
_eleBufferDict[setId].ForEach(e => cvImage.Elements.Add(e));
|
||||
|
||||
_eleBufferDict.Remove(setId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
6598
src/BRS.Common.Device/DeviceBase/UI/CtrlCameraRunBase.resx
Normal file
6598
src/BRS.Common.Device/DeviceBase/UI/CtrlCameraRunBase.resx
Normal file
File diff suppressed because it is too large
Load Diff
423
src/BRS.Common.Device/DeviceBase/VisionEngineBase.cs
Normal file
423
src/BRS.Common.Device/DeviceBase/VisionEngineBase.cs
Normal file
@ -0,0 +1,423 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using BRS.Common.Model.Forms;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.Design;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
/// <summary>
|
||||
/// 视觉处理引擎:1.传统视觉 2.深度学习
|
||||
/// CV深度学习 四大领域
|
||||
/// Image Classification 图像分类:判别图中物体是什么,比如是猫还是狗;
|
||||
/// Semantic Segmentation 语义分割:对图像进行像素级分类,预测每个像素属于的类别,不区分个体;
|
||||
/// Object Detection 目标检测:寻找图像中的物体并进行定位;
|
||||
/// Instance Segmentation 实例分割:定位图中每个物体,并进行像素级标注,区分不同个体;
|
||||
/// </summary>
|
||||
public abstract class VisionEngineBase : DeviceBase
|
||||
{
|
||||
#region event
|
||||
public event Action<string, Bitmap, List<IShapeElement>> OnDetectionDone;
|
||||
#endregion
|
||||
|
||||
public VisionEngineInitialConfigBase IConfig
|
||||
{
|
||||
get => InitialConfig as VisionEngineInitialConfigBase;
|
||||
}
|
||||
|
||||
public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
|
||||
public string BatchNO { get; set; }
|
||||
|
||||
|
||||
public abstract Task<DetectStationResult> RunInferenceAsync(IImageSet originImgSet, string detectionId = null);
|
||||
|
||||
|
||||
public abstract DetectStationResult RunInference(IImageSet originImgSet, string detectionId = null);
|
||||
|
||||
|
||||
|
||||
public abstract void OFFLineRunInference(List<OFFLineDetectSet> offLineDetectSets);
|
||||
|
||||
|
||||
public virtual void DetectionDone(string detectionId, Bitmap image, List<IShapeElement> detectionResults)
|
||||
{
|
||||
OnDetectionDone?.Invoke(detectionId, image, detectionResults);
|
||||
}
|
||||
|
||||
public virtual void SaveImageAsync(string fullname, Bitmap saveMap, ImageFormat imageFormat)
|
||||
{
|
||||
if (saveMap != null)
|
||||
{
|
||||
ImageSaveSet imageSaveSet = new ImageSaveSet()
|
||||
{
|
||||
FullName = fullname,
|
||||
SaveImage = saveMap.CopyBitmap(),
|
||||
//ImageFormat = imageFormat.DeepSerializeClone()
|
||||
};
|
||||
|
||||
ImageSaveHelper.ImageSaveAsync(imageSaveSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class VisionEngineInitialConfigBase : InitialConfigBase
|
||||
{
|
||||
[Category("视觉检测配置")]
|
||||
[DisplayName("检测配置集合")]
|
||||
[Description("检测配置集合")]
|
||||
[TypeConverter(typeof(CollectionCountConvert))]
|
||||
[Editor(typeof(ComplexCollectionEditor<DetectionConfig>), typeof(UITypeEditor))]
|
||||
public List<DetectionConfig> DetectionConfigs { get; set; } = new List<DetectionConfig>();
|
||||
|
||||
|
||||
[Category("视觉检测配置")]
|
||||
[Description("检测图片 保存文件夹")]
|
||||
[DisplayName("检测图片保存文件夹")]
|
||||
[Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))]
|
||||
// [Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string ImageSaveDirectory { get; set; } = "D:\\PROJECTS\\A020\\Images";
|
||||
|
||||
|
||||
|
||||
[Category("视觉检测配置")]
|
||||
[DisplayName("是否保存检测图片")]
|
||||
[Description("是否保存 检测图片,总开关")]
|
||||
public bool IsSaveImage { get; set; } = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检测项配置
|
||||
/// </summary>
|
||||
public class DetectionConfig : IComplexDisplay
|
||||
{
|
||||
[ReadOnly(true)]
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[Category("检测配置")]
|
||||
[DisplayName("检测配置名称")]
|
||||
[Description("检测配置名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 推理设备,包括CPU GPU VPU
|
||||
/// </summary>
|
||||
[Category("检测配置")]
|
||||
[DisplayName("推理设备")]
|
||||
[Description("选择推理设备。")]
|
||||
[TypeConverter(typeof(EnumDescriptionConverter<DetectionDeviceTypeDef>))]
|
||||
public DetectionDeviceTypeDef DetectionDeviceType { get; set; }
|
||||
|
||||
|
||||
|
||||
//[Category("检测配置")]
|
||||
//[DisplayName("设备名称")]
|
||||
//[Description("选择检测设备,包括GPU、CPU等")]
|
||||
//public string DetectionDeviceType { get; set; } = "CPU";
|
||||
|
||||
|
||||
|
||||
|
||||
[Category("检测配置")]
|
||||
[DisplayName("预热图片路径配置")]
|
||||
[Description("预热图片路径配置")]
|
||||
[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string PreheatImagePath { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
[Category("原始图片保存设置")]
|
||||
[Description("视觉检测 图片保存配置")]
|
||||
[DisplayName("图片保存配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public virtual VisionImageSaveOption ImageSaveOption { get; set; } = new VisionImageSaveOption();
|
||||
|
||||
|
||||
[Category("深度学习检测配置")]
|
||||
[DisplayName("目标检测-模型路径")]
|
||||
[Description("目标检测-配置文件路径,onnx")]
|
||||
[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string MLModelPath { get; set; }
|
||||
|
||||
|
||||
[Category("深度学习检测配置")]
|
||||
[DisplayName("目标检测-标签路径")]
|
||||
[Description("目标检测-配置标签路径,TEXT")]
|
||||
[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
public string MLLablePath { get; set; }
|
||||
|
||||
[Category("深度学习检测配置")]
|
||||
[DisplayName("检测置信度")]
|
||||
[Description("配置模型置信度")]
|
||||
public float confThreshold { get; set; } = 0.3f;
|
||||
|
||||
[Category("深度学习检测配置")]
|
||||
[DisplayName("检测IOU")]
|
||||
[Description("配置IOU")]
|
||||
public float iouThreshold { get; set; } = 0.4f;
|
||||
|
||||
//[Category("深度学习检测配置")]
|
||||
//[DisplayName("目标检测-启动GPU")]
|
||||
//[Description("目标检测-启动GPU")]
|
||||
//public bool bGPU { get; set; } = false;
|
||||
|
||||
|
||||
//[Category("深度学习检测配置")]
|
||||
//[DisplayName("是否保存检测图片")]
|
||||
//[Description("是否保存 检测图片,总开关")]
|
||||
//public bool IsSaveImage { get; set; } = true;
|
||||
|
||||
|
||||
//[Category("深度学习检测配置")]
|
||||
//[Description("检测图片 保存文件夹")]
|
||||
//[DisplayName("检测图片保存文件夹")]
|
||||
//[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
//public string ImageSaveDirectory { get; set; } = "D:\\PROJECTS\\A020\\Images\\Result\\";
|
||||
|
||||
[Category("深度学习检测配置")]
|
||||
[DisplayName("是否启用该检测")]
|
||||
[Description("是否启用该检测")]
|
||||
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
|
||||
|
||||
//[Category("图像参数设置")]
|
||||
//[DisplayName("图片重采样大小")]
|
||||
//[Description("模型适配图片重采样大小")]
|
||||
//public int ImageResizeCount { get; set; } = 640;
|
||||
|
||||
|
||||
|
||||
[Category("模型架构参数配置")]
|
||||
[DisplayName("输入节点名称")]
|
||||
[Description("输入节点名称")]
|
||||
public string in_node_name { get; set; } = "images";
|
||||
|
||||
[Category("模型架构参数配置")]
|
||||
[DisplayName("输出节点名称")]
|
||||
[Description("输出节点名称")]
|
||||
public string out_node_name { get; set; } = "output";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ========================================
|
||||
|
||||
|
||||
//[Category("图像参数设置")]
|
||||
//[DisplayName("原始图像大小")]
|
||||
//[Description("模型适配图片重采样大小")]
|
||||
//public int ImageSize { get; set; } = 640;
|
||||
|
||||
|
||||
// ========================================
|
||||
|
||||
[Category("推理参数设置")]
|
||||
[DisplayName("图片通道数")]
|
||||
[Description("图片通道数")]
|
||||
public ulong ImageChannels { get; set; } = 3;
|
||||
|
||||
|
||||
// batch
|
||||
//[ReadOnly(true)]
|
||||
//[Category("推理参数设置")]
|
||||
//[DisplayName("图片通道数")]
|
||||
//[Description("原始图片通道")]
|
||||
//public ulong ImageBatchNum { get; set; } = 1;
|
||||
|
||||
|
||||
[Category("推理参数设置")]
|
||||
[DisplayName("推理图片宽度")]
|
||||
[Description("推理图片宽度,单位:像素")]
|
||||
public ulong ImageWidth { get; set; } = 640;
|
||||
|
||||
|
||||
[Category("推理参数设置")]
|
||||
[DisplayName("推理图片高度")]
|
||||
[Description("推理图片高度,单位:像素")]
|
||||
public ulong ImageHeight { get; set; } = 640;
|
||||
|
||||
// ========================================
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//[Category("图像预处理检测配置")]
|
||||
//[DisplayName("是否启用该检测")]
|
||||
//[Description("是否启用该检测")]
|
||||
|
||||
//public bool preIsEnabled { get; set; }
|
||||
|
||||
|
||||
//[Category("图像预处理检测配置")]
|
||||
//[DisplayName("是否加载模型")]
|
||||
//[Description("是否启用该模型")]
|
||||
|
||||
//public bool IspreLoadModel{ get; set; }
|
||||
|
||||
|
||||
|
||||
//[Category("图像预处理检测配置")]
|
||||
//[Description("预处理加载模型算法配置")]
|
||||
//[DisplayName("预处理加载模型文件配置")]
|
||||
//[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
//public string preProcessLMFilePath { get; set; } = "D:\\PROJECTS\\A020\\Model\\Pre\\";
|
||||
|
||||
|
||||
|
||||
//[Category("图像预处理检测配置")]
|
||||
//[Description("预处理算法路径配置")]
|
||||
//[DisplayName("预处理算法文件配置")]
|
||||
//[Editor(typeof(FileDialogEditor), typeof(UITypeEditor))]
|
||||
//public string preProcessFilePath { get; set; } = "D:\\PROJECTS\\A020\\Model\\Pre\\";
|
||||
[Category("关联相机")]
|
||||
[DisplayName("关联相机")]
|
||||
[Description("关联相机描述")]
|
||||
[TypeConverter(typeof(DeviceIdSelectorConverter<CameraBase>))]
|
||||
public string CameraSourceId { get; set; } = "";
|
||||
|
||||
[Category("显示配置")]
|
||||
[DisplayName("显示检测图片及信息")]
|
||||
[Description("true:检测图片/信息显示在运行界面;false:不显示检测图片/信息")]
|
||||
public bool IsShowInUI { get; set; } = true;
|
||||
|
||||
[Category("显示配置")]
|
||||
[DisplayName("显示位置")]
|
||||
[Description("检测信息显示位置。左上角为(1,1),向右向下为正方向")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public CustomizedPoint ShowLocation { get; set; } = new CustomizedPoint();
|
||||
|
||||
[Category("显示配置")]
|
||||
[DisplayName("图片所占布局的列数")]
|
||||
[Description("图片所占布局的列数")]
|
||||
public int ColumnSpan { get; set; } = 1;
|
||||
|
||||
[Category("显示配置")]
|
||||
[DisplayName("图片所占布局的行数")]
|
||||
[Description("图片所占布局的行数")]
|
||||
public int RowSpan { get; set; } = 1;
|
||||
|
||||
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return $"{(IsEnabled ? "启用" : "禁用 ")}-{Name}";
|
||||
}
|
||||
|
||||
|
||||
public void SetImageSaveDirectory()
|
||||
{
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
IProcessConfig config = scope.Resolve<IProcessConfig>();
|
||||
var mlBase = config.DeviceConfigs.FirstOrDefault(u => u is VisionEngineInitialConfigBase);
|
||||
if (mlBase != null)
|
||||
{
|
||||
var iConfig = mlBase as VisionEngineInitialConfigBase;
|
||||
ImageSaveOption.ImageSaveDirectory = iConfig.ImageSaveDirectory;
|
||||
ImageSaveOption.IsEnabled = iConfig.IsSaveImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class VisionEngineOperationConfigBase : OperationConfigBase
|
||||
{
|
||||
//[Category("图像来源")]
|
||||
//[DisplayName("是否离线图片")]
|
||||
//[Description("true:离线图片 false:在线采图")]
|
||||
//public bool IsImageOffline { get; set; } = false;
|
||||
|
||||
[Browsable(false)]
|
||||
public bool IsBatchOffline { get; set; } = false;
|
||||
|
||||
[Browsable(false)]
|
||||
public string BatchOfflineImgDirectory { get; set; }
|
||||
|
||||
[Category("采图操作")]
|
||||
[DisplayName("采图相机")]
|
||||
[Description("采图使用的相机")]
|
||||
[TypeConverter(typeof(DeviceIdSelectorConverter<CameraBase>))]
|
||||
public string CameraSourceId { get; set; }
|
||||
|
||||
[Category("采图操作")]
|
||||
[DisplayName("相机操作配置")]
|
||||
[Description("采图相机操作配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(VisionSnapOpConfigEditor), typeof(UITypeEditor))]
|
||||
public IOperationConfig CameraOpConfig { get; set; }
|
||||
|
||||
|
||||
[Category("保存设置")]
|
||||
[DisplayName("检测图片 附加配置")]
|
||||
[Description("检测图片 附加配置")]
|
||||
[TypeConverter(typeof(ComplexObjectConvert))]
|
||||
[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
|
||||
public VisionImageSaveOption ImageSaveOption { get; set; } = new VisionImageSaveOption();
|
||||
|
||||
}
|
||||
|
||||
public class OFFLineDetectSet
|
||||
{
|
||||
public List<IImageSet> ImageSetList { get; set; }
|
||||
public string DetectionConfigId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class VisionSnapOpConfigEditor : UITypeEditor
|
||||
{
|
||||
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
|
||||
{
|
||||
return UITypeEditorEditStyle.Modal;
|
||||
}
|
||||
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
|
||||
|
||||
if (edSvc != null)
|
||||
{
|
||||
VisionEngineOperationConfigBase mlOpConfig = context.Instance as VisionEngineOperationConfigBase;
|
||||
|
||||
FrmDeviceOpConfigEditor frmDeviceOpEditor = new FrmDeviceOpConfigEditor(new DeviceOpBind() { Device = mlOpConfig.CameraSourceId, OpConfig = value as IOperationConfig }, "")
|
||||
{
|
||||
StartPosition = FormStartPosition.CenterScreen
|
||||
};
|
||||
frmDeviceOpEditor.ShowDialog();
|
||||
|
||||
return frmDeviceOpEditor.Bind.OpConfig;
|
||||
}
|
||||
|
||||
return base.EditValue(context, provider, value);
|
||||
}
|
||||
}
|
||||
}
|
186
src/BRS.Common.Device/Helper/AspectHelper.cs
Normal file
186
src/BRS.Common.Device/Helper/AspectHelper.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using ArxOne.MrAdvice.Advice;
|
||||
using BRS.Common.Base;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public static class JsonHelper
|
||||
{
|
||||
public static JsonSerializerSettings JsonSetWithType = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All };
|
||||
}
|
||||
|
||||
#region PostSharp AOP related
|
||||
|
||||
/// <summary>
|
||||
/// 工序设备运行 环切面 用于修饰DeviceBase的SetAndRun
|
||||
/// </summary>
|
||||
public class DeviceRunAroundAspect : Attribute, IMethodAdvice
|
||||
{
|
||||
public void Advise(MethodAdviceContext context)
|
||||
{
|
||||
// do things you want here(before)
|
||||
OnEntry(context);
|
||||
// this calls the original method(now)
|
||||
context.Proceed();
|
||||
// do other things here(after)
|
||||
OnSuccess(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备操作前
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
public void OnEntry(MethodAdviceContext args)
|
||||
{
|
||||
#region 检查设备状态
|
||||
DeviceBase device = args.Target as DeviceBase;
|
||||
if (device.CurrentState != EnumHelper.DeviceState.DSOpen)
|
||||
{
|
||||
throw new ProcessException($"{device.Name}不在开启状态,无法操作!");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 启用日志
|
||||
device.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{device.Name}开始{args.TargetMethod.Name}");
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备完成操作后
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
public void OnSuccess(MethodAdviceContext args)
|
||||
{
|
||||
DeviceBase device = args.Target as DeviceBase;
|
||||
|
||||
#region 完成日志
|
||||
device.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{device.Name}完成{args.TargetMethod.Name}");
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备异常捕获 切面
|
||||
/// </summary>
|
||||
public class DeviceExceptionAspect : Attribute, IMethodAdvice
|
||||
{
|
||||
public void Advise(MethodAdviceContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
context.Proceed();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException(context, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnException(MethodAdviceContext args, Exception exception)
|
||||
{
|
||||
DeviceBase device = args.Target as DeviceBase;
|
||||
if (device.CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
device.CurrentState = EnumHelper.DeviceState.DSExcept;
|
||||
device.CurrentStateToBe = EnumHelper.DeviceState.DSExcept;
|
||||
|
||||
|
||||
#region 通知设备的状态变动
|
||||
device.OnExceptionOccured?.Invoke(DateTime.Now, exception);
|
||||
#endregion
|
||||
|
||||
#region 异常日志记录
|
||||
device.LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"{device.Name} {args.TargetMethod.Name}异常信息{exception.GetExceptionMessage()}");
|
||||
#endregion
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 方法开始前捕获 切面
|
||||
/// </summary>
|
||||
public class DeviceOnEntryAspect : Attribute, IMethodAdvice
|
||||
{
|
||||
public void Advise(MethodAdviceContext context)
|
||||
{
|
||||
OnEntry(context);
|
||||
context.Proceed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备操作前
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
public void OnEntry(MethodAdviceContext args)
|
||||
{
|
||||
#region 检查设备状态
|
||||
DeviceBase device = args.Target as DeviceBase;
|
||||
if (device.CurrentState != EnumHelper.DeviceState.DSOpen)
|
||||
{
|
||||
throw new ProcessException($"{device.Name}不在开启状态,无法操作!");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 启用日志
|
||||
device.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{device.Name}开始{args.TargetMethod.Name}");
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 方法结束后捕获 切面
|
||||
/// </summary>
|
||||
public class DeviceOnSuccessAspect : Attribute, IMethodAdvice
|
||||
{
|
||||
public void Advise(MethodAdviceContext context)
|
||||
{
|
||||
context.Proceed();
|
||||
OnSuccess(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备完成操作后
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
public void OnSuccess(MethodAdviceContext args)
|
||||
{
|
||||
DeviceBase device = args.Target as DeviceBase;
|
||||
|
||||
#region 完成日志
|
||||
device.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{device.Name}完成{args.TargetMethod.Name}");
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流程异常捕获切面
|
||||
/// </summary>
|
||||
public class ProcessExceptionAspect : Attribute, IMethodAdvice
|
||||
{
|
||||
public void Advise(MethodAdviceContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
context.Proceed();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnException(context, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnException(MethodAdviceContext args, Exception exception)
|
||||
{
|
||||
//Exception ex = exception;
|
||||
|
||||
//if (!(ex is ProcessException))
|
||||
//{
|
||||
// new ProcessException(ex);
|
||||
//}
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
131
src/BRS.Common.Device/Helper/SerialPortHelper.cs
Normal file
131
src/BRS.Common.Device/Helper/SerialPortHelper.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Device.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// 串口助手,管理项目中用到的所有串口设备
|
||||
/// </summary>
|
||||
public static class SerialPortHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 静态对象,存储当前软件中用到的所有串口端口
|
||||
/// </summary>
|
||||
public static List<SerialPort> UsingPorts { get; set; } = new List<SerialPort>();
|
||||
|
||||
static object _spLock = new object();
|
||||
|
||||
static Dictionary<string, object> _opLock = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// 打开串口
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="errorMsg"></param>
|
||||
/// <returns></returns>
|
||||
public static bool StartPort(ref SerialPort port, out string errorMsg)
|
||||
{
|
||||
errorMsg = "";
|
||||
try
|
||||
{
|
||||
lock (_spLock)
|
||||
{
|
||||
string portName = port.PortName;
|
||||
SerialPort usingPort = UsingPorts.FirstOrDefault(u => u.PortName == portName);
|
||||
if (usingPort == null)
|
||||
{
|
||||
usingPort = port;
|
||||
UsingPorts.Add(usingPort);
|
||||
|
||||
_opLock[portName] = new object();
|
||||
}
|
||||
|
||||
if (!usingPort.IsOpen)
|
||||
{
|
||||
usingPort.Open();
|
||||
}
|
||||
|
||||
port = usingPort;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMsg = ex.Message;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ClosePort(string portName, out string errorMsg)
|
||||
{
|
||||
errorMsg = "";
|
||||
|
||||
try
|
||||
{
|
||||
lock (_spLock)
|
||||
{
|
||||
SerialPort usingPort = UsingPorts.FirstOrDefault(u => u.PortName == portName);
|
||||
if (usingPort != null && usingPort.IsOpen)
|
||||
{
|
||||
usingPort.Close();
|
||||
UsingPorts.RemoveAll(u => u.PortName == portName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMsg = ex.Message;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Write(SerialPort port, byte[] data, int startAddress, int length, int waitTime = 50)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_opLock[port.PortName])
|
||||
{
|
||||
port.Write(data, startAddress, length);
|
||||
|
||||
if (waitTime > 0)
|
||||
{
|
||||
//Task.Delay(waitTime);
|
||||
Thread.Sleep(waitTime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadExisting(SerialPort port)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_opLock[port.PortName])
|
||||
{
|
||||
return port.ReadExisting();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
50
src/BRS.Common.Device/Interface/IMotion.cs
Normal file
50
src/BRS.Common.Device/Interface/IMotion.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
/// <summary>
|
||||
/// 运动机构接口 具体由PLC/板卡实现
|
||||
/// </summary>
|
||||
public interface IMotion
|
||||
{
|
||||
List<AxisInfo> GetCurrentAxisInfo(params string[] axisName);
|
||||
|
||||
/// <summary>
|
||||
/// 运动机构点到点移动
|
||||
/// </summary>
|
||||
/// <param name="opConfig">运动配置</param>
|
||||
/// <returns>true:正常结束 false:异常结束</returns>
|
||||
ResponseMessage MoveToPoint(IOperationConfig opConfig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 板卡接口
|
||||
/// </summary>
|
||||
public interface IMotionCard : IMotion
|
||||
{
|
||||
/// <summary>
|
||||
/// 板卡执行动作 除了运动动作外还包含IO操作
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
ResponseMessage Run(IOperationConfig config);
|
||||
}
|
||||
|
||||
public class AxisInfo : IComplexDisplay
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
public double AxisLocation { get; set; }
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
return $"{AxisName}:{AxisLocation}";
|
||||
}
|
||||
}
|
||||
}
|
15
src/BRS.Common.Device/Interface/IVibrationSupplier.cs
Normal file
15
src/BRS.Common.Device/Interface/IVibrationSupplier.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using BRS.Common.Model;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 振动盘供料器
|
||||
/// </summary>
|
||||
public interface IVibrationSupplier
|
||||
{
|
||||
bool StartVibration();
|
||||
bool StopVibration();
|
||||
|
||||
ResponseMessage Adjust(IOperationConfig opConfig);
|
||||
}
|
||||
}
|
35
src/BRS.Common.Device/Properties/AssemblyInfo.cs
Normal file
35
src/BRS.Common.Device/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("BRS.Common")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("BRS.Common")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("987308dd-8baa-463a-94e2-77d62e01a5bf")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
63
src/BRS.Common.Device/Properties/Resources.Designer.cs
generated
Normal file
63
src/BRS.Common.Device/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace BRS.Common.Device.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <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("BRS.Common.Device.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
src/BRS.Common.Device/Properties/Resources.resx
Normal file
120
src/BRS.Common.Device/Properties/Resources.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
19
src/BRS.Common.Device/app.config
Normal file
19
src/BRS.Common.Device/app.config
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1"/>
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup></configuration>
|
17
src/BRS.Common.Device/packages.config
Normal file
17
src/BRS.Common.Device/packages.config
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="4.9.4" targetFramework="net472" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net472" />
|
||||
<package id="MrAdvice" version="2.9.7" targetFramework="net462" />
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net462" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="4.7.1" targetFramework="net472" />
|
||||
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
|
||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="7.0.0-preview.2.22152.2" targetFramework="net462" requireReinstallation="true" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net462" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net462" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net462" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net462" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
|
||||
</packages>
|
108
src/BRS.Common.Model/Authority/AuthorityCheck.cs
Normal file
108
src/BRS.Common.Model/Authority/AuthorityCheck.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using SuperDog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Model.Authority
|
||||
{
|
||||
public static class AuthorityCheck
|
||||
{
|
||||
public static Timer AuthorityCheckTimer = null;
|
||||
public static UdpClient RemoteCheckClient = null;
|
||||
static byte[] CHECKBUFFER = null;
|
||||
static IPEndPoint AuthorityServer = null;
|
||||
public static bool IsAuthorityOK { get; set; } = false;
|
||||
|
||||
static bool _isCheckAuthorityNecessary = true;
|
||||
static AuthorityCheck()
|
||||
{
|
||||
AuthorityCheckTimer = new Timer(OnAuthorityCheck, null, 0, 1000 * 60);
|
||||
RemoteCheckClient = new UdpClient();
|
||||
RemoteCheckClient.EnableBroadcast = true;
|
||||
RemoteCheckClient.Client.ReceiveTimeout = 1000;
|
||||
|
||||
CHECKBUFFER = System.Text.Encoding.UTF8.GetBytes("AuthorityCheck");
|
||||
|
||||
string checkStr = ConfigurationManager.AppSettings["AuthorityCheck"];
|
||||
if (bool.TryParse(checkStr ?? "true", out bool temp))
|
||||
{
|
||||
_isCheckAuthorityNecessary = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isCheckAuthorityNecessary = true;
|
||||
}
|
||||
|
||||
string server = ConfigurationManager.AppSettings["AuthorityServer"];
|
||||
if (string.IsNullOrWhiteSpace(server))
|
||||
{
|
||||
server = "192.168.1.255:11001"; //默认1网段广播 端口11001
|
||||
}
|
||||
|
||||
string[] serverData = server.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string ipAddress = serverData[0];
|
||||
int port = 11001;
|
||||
|
||||
if (serverData.Length > 1 && int.TryParse(serverData[1], out int portTemp))
|
||||
{
|
||||
port = portTemp;
|
||||
}
|
||||
|
||||
AuthorityServer = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
||||
}
|
||||
|
||||
private static void OnAuthorityCheck(object state)
|
||||
{
|
||||
AuthorityCheckOperation();
|
||||
}
|
||||
|
||||
public static bool AuthorityCheckOperation()
|
||||
{
|
||||
if (!_isCheckAuthorityNecessary)
|
||||
{
|
||||
IsAuthorityOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DogFeature feature = new DogFeature(1);
|
||||
DogStatus status = DogStatus.StatusOk;
|
||||
using (var dog = new Dog(feature))
|
||||
{
|
||||
string vendorCodes = "FIgWctNxfC4kOOrFk52ktOm6JBRreMTI2ckQRUwjJmzstXN2awbyKGfjdlWcKFpjMiJRwirzPlJKSThN1nC7axSY4Y9l5+aRzCYI8WoYFmtx4zBx2n1fQ9Rb/CGk99Z9mM5mpZQVH+PGmZGsEjfSBdY12HjIcPVHGmMyecskMlhIGxDqUg8ndCk8/0fqexKbQCffDiGAPbxZgxKlRAnxJFOwd1V2Hmq3Iln1YNhyRRbgudU7kPCY/RsxBKXtL4wym96d2jQNDcKV8A5Anb4UlSLbac7OcrCZEBSUTpMjyDYRvDWFWTmfVKX9/vuI4VvKjr2t/wt01Nu0tQ0a4AVtQZk+l13WZkwkkeOUh6gtvVFJZH61hpwhOOjnN9dNw8WSYBYC/NyaMjiv7yRVHt9K/Bs76T8I0ias55BP1GXe6C+zGJ9KXK+baCLojMTObj3Bs9JFhDwEDgEjRDCxz9POZnE3XPe/2ET4KbRP5cXZsX7rxbnwQ33E/cKcG1hidG3RTLu7d+IRob9vgpeeUYXB8OHSoReJBsjhJEWBCDko9YnTb1FcO0YwPQdxW0BaVf1n6XAXlPUA6cGP552Kp3F0pcIxVKKGpYUeDL7oIFQrtnJ5aW7mB+/c35BDTCueM8wQIJ3b2KOI+lueC+dbhpHffVgtPnrh/atxcZxUoM2/KxjvniCYtUOKbeYh8Gqn1MDk1bAO2B9KNBrbGuWJpgDTfZunE/ZVtd09clExYJ8NW2Lw6pfNB3nbh1MlRUmmhQPIDubOnjiaBVbCQGF6Nm4/M0aIywSPJCMPaXK0sso5v+EDM4frryOPkvBEAbDyIuU+yQkO9vnYggKLAezyxZNxVqQgXcMaS0WyJxZxjFku7/Os8YU5z54DeOu6zDRD4zAjUKT7JIQcJKvtYGVB5lvirKDqISzDjsHcq4NJyQbQzg462y9o90ljUwCCMJrBmOw4NHpYKTNypN8aCsYmiebwag==";
|
||||
status = dog.Login(vendorCodes, "<dogscope />");
|
||||
}
|
||||
|
||||
if (status == DogStatus.StatusOk)
|
||||
{
|
||||
IsAuthorityOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsAuthorityOK = false;
|
||||
try
|
||||
{
|
||||
RemoteCheckClient.Send(CHECKBUFFER, CHECKBUFFER.Length, AuthorityServer);
|
||||
|
||||
IPEndPoint ep = null;
|
||||
var recBuffer = RemoteCheckClient.Receive(ref ep);
|
||||
var recStr = System.Text.Encoding.UTF8.GetString(recBuffer);
|
||||
|
||||
IsAuthorityOK = (recStr == "AuthorityOK");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"远程权限检测失败,{ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IsAuthorityOK;
|
||||
}
|
||||
}
|
||||
}
|
264
src/BRS.Common.Model/BRS.Common.Model.csproj
Normal file
264
src/BRS.Common.Model/BRS.Common.Model.csproj
Normal file
@ -0,0 +1,264 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\packages\OpenCvSharp4.runtime.win.4.6.0.20220608\build\netstandard\OpenCvSharp4.runtime.win.props" Condition="Exists('..\..\packages\OpenCvSharp4.runtime.win.4.6.0.20220608\build\netstandard\OpenCvSharp4.runtime.win.props')" />
|
||||
<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>{1A3CBFE7-3F78-42C3-95C5-10360450DBEA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>BRS.Common.Model</RootNamespace>
|
||||
<AssemblyName>BRS.Common.Model</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug1|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\Debug1\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug1|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug1\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=4.9.4.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Autofac.4.9.4\lib\net45\Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="dog_net_windows">
|
||||
<HintPath>..\..\libs\SafetyDog\dog_net_windows.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\OpenCvSharp4.4.6.0.20220608\lib\netstandard2.0\OpenCvSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\OpenCvSharp4.Extensions.4.6.0.20220608\lib\netstandard2.0\OpenCvSharp.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.7.1\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Drawing.Common, Version=4.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Drawing.Common.5.0.3\lib\net461\System.Drawing.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.7.0.0-preview.2.22152.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Windows.Forms.DataVisualization" />
|
||||
<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="Authority\AuthorityCheck.cs" />
|
||||
<Compile Include="Base\DeviceConfigBase.cs" />
|
||||
<Compile Include="Exception\IExceptionHandler.cs" />
|
||||
<Compile Include="Factory\ConfigFactory.cs" />
|
||||
<Compile Include="Factory\DeviceFactory.cs" />
|
||||
<Compile Include="Factory\ElementFactory.cs" />
|
||||
<Compile Include="Factory\FactoryHelper.cs" />
|
||||
<Compile Include="Factory\ProcessFactory.cs" />
|
||||
<Compile Include="Factory\UIFactory.cs" />
|
||||
<Compile Include="Forms\FrmDeviceOpConfigEditor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\FrmDeviceOpConfigEditor.Designer.cs">
|
||||
<DependentUpon>FrmDeviceOpConfigEditor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forms\FrmOpConfigEdit.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\FrmOpConfigEdit.Designer.cs">
|
||||
<DependentUpon>FrmOpConfigEdit.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GlobalVar.cs" />
|
||||
<Compile Include="Helper\AttributeHelper.cs" />
|
||||
<Compile Include="Helper\ChartHelper.cs" />
|
||||
<Compile Include="Helper\CPUHelper.cs" />
|
||||
<Compile Include="Helper\ImageSaveHelper.cs" />
|
||||
<Compile Include="Helper\EnumHelper.cs" />
|
||||
<Compile Include="Exception\ExceptionHelper.cs" />
|
||||
<Compile Include="Helper\JsonHelper.cs" />
|
||||
<Compile Include="Helper\ListHelper.cs" />
|
||||
<Compile Include="Helper\PropertyConvertHelper.cs" />
|
||||
<Compile Include="Helper\SettingHelper.cs" />
|
||||
<Compile Include="Helper\StaticHelper.cs" />
|
||||
<Compile Include="Helper\TimeOutHelper.cs" />
|
||||
<Compile Include="Helper\UIHelper.cs" />
|
||||
<Compile Include="Helper\WebApiHelper.cs" />
|
||||
<Compile Include="Helper\WebServiceHelper.cs" />
|
||||
<Compile Include="Interface\IImageSet.cs" />
|
||||
<Compile Include="Interface\IIOModuleConfig.cs" />
|
||||
<Compile Include="Interface\IMenuNode.cs" />
|
||||
<Compile Include="Interface\IConfigCtrl.cs" />
|
||||
<Compile Include="Interface\ICSVOutput.cs" />
|
||||
<Compile Include="Interface\IDevice.cs" />
|
||||
<Compile Include="Interface\IDeviceConfig.cs" />
|
||||
<Compile Include="Interface\IHalconToolPath.cs" />
|
||||
<Compile Include="Interface\IInputConfig.cs" />
|
||||
<Compile Include="Interface\IMonitor.cs" />
|
||||
<Compile Include="Interface\IProductData.cs" />
|
||||
<Compile Include="Interface\IRemoteMessage.cs" />
|
||||
<Compile Include="Interface\IWarningSetCollection.cs" />
|
||||
<Compile Include="Interface\IMonitorSetCollection.cs" />
|
||||
<Compile Include="Interface\IOperationConfig.cs" />
|
||||
<Compile Include="Interface\IProcessConfig.cs" />
|
||||
<Compile Include="Interface\IProcess.cs" />
|
||||
<Compile Include="Interface\IRunCtrl.cs" />
|
||||
<Compile Include="Interface\IShapeElement.cs" />
|
||||
<Compile Include="Helper\CSVHelper.cs" />
|
||||
<Compile Include="Interface\ILogger.cs" />
|
||||
<Compile Include="Helper\LoggerHelper.cs" />
|
||||
<Compile Include="Model\CustomizedPoint.cs" />
|
||||
<Compile Include="Model\CustomizedRectangle.cs" />
|
||||
<Compile Include="Model\DeviceOpBind.cs" />
|
||||
<Compile Include="Model\DynamicModel.cs" />
|
||||
<Compile Include="Model\LaserScanParam.cs" />
|
||||
<Compile Include="Model\ModbusFrame.cs" />
|
||||
<Compile Include="Model\MonitorSet.cs" />
|
||||
<Compile Include="Model\MotionCardRelated.cs" />
|
||||
<Compile Include="Model\PageRequest.cs" />
|
||||
<Compile Include="Model\IOItem.cs" />
|
||||
<Compile Include="Model\PLCItem.cs" />
|
||||
<Compile Include="Model\ProcessResponse.cs" />
|
||||
<Compile Include="Model\ProductSummary.cs" />
|
||||
<Compile Include="Model\ResponseMessage.cs" />
|
||||
<Compile Include="Model\Spec.cs" />
|
||||
<Compile Include="Model\VisionRelated.cs" />
|
||||
<Compile Include="Model\UPHModel.cs" />
|
||||
<Compile Include="Model\VelocityParams.cs" />
|
||||
<Compile Include="Model\WaitConfirm.cs" />
|
||||
<Compile Include="Model\WarningSet.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PubSub\IPublisher.cs" />
|
||||
<Compile Include="PubSub\IPubSubCenter.cs" />
|
||||
<Compile Include="PubSub\ISubscriber.cs" />
|
||||
<Compile Include="PubSub\PubSubCenter.cs" />
|
||||
<Compile Include="PubSub\SimplePubSubCenter.cs" />
|
||||
<Compile Include="PubSub\SimpleSubscriber.cs" />
|
||||
<Compile Include="Selector\DeviceSelector.cs" />
|
||||
<Compile Include="Selector\ProcessMethodSelector.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Forms\FrmDeviceOpConfigEditor.resx">
|
||||
<DependentUpon>FrmDeviceOpConfigEditor.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\FrmOpConfigEdit.resx">
|
||||
<DependentUpon>FrmOpConfigEdit.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="api_dsp_windows.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="api_dsp_windows_x64.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dog_windows_3153818.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dog_windows_x64_3153818.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\OpenCvSharp4.runtime.win.4.6.0.20220608\build\netstandard\OpenCvSharp4.runtime.win.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\OpenCvSharp4.runtime.win.4.6.0.20220608\build\netstandard\OpenCvSharp4.runtime.win.props'))" />
|
||||
</Target>
|
||||
</Project>
|
274
src/BRS.Common.Model/Base/DeviceBase.cs
Normal file
274
src/BRS.Common.Model/Base/DeviceBase.cs
Normal file
@ -0,0 +1,274 @@
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using static Bro.Common.Helper.EnumHelper;
|
||||
|
||||
namespace Bro.Common.Base
|
||||
{
|
||||
public abstract class DeviceBase : IDevice
|
||||
{
|
||||
#region Event
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public Action<DateTime, Exception> OnExceptionOccured { get; set; }
|
||||
public event Action<DateTime, IDevice, string> OnLog;
|
||||
public event Action<IDevice, DeviceState> OnDeviceStateChanged;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
#endregion
|
||||
|
||||
#region field
|
||||
int RetryTime = 3;
|
||||
/// <summary>
|
||||
/// 和设备暂停状态关联的信号量
|
||||
/// </summary>
|
||||
private ManualResetEvent pauseHandle = new ManualResetEvent(true);
|
||||
Timer stateChangedTimer;
|
||||
#endregion
|
||||
|
||||
#region Property
|
||||
#region State
|
||||
private EnumHelper.DeviceState _currentStateToBe = EnumHelper.DeviceState.DSUninit;
|
||||
/// <summary>
|
||||
/// 当前设备状态
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
internal EnumHelper.DeviceState CurrentStateToBe
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentStateToBe;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _currentStateToBe)
|
||||
{
|
||||
var initialState = _currentStateToBe;
|
||||
_currentStateToBe = value;
|
||||
|
||||
if (_currentStateToBe != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
OnStateChanged(initialState);
|
||||
}
|
||||
else
|
||||
{
|
||||
stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EnumHelper.DeviceState initialState = EnumHelper.DeviceState.DSUninit;
|
||||
private EnumHelper.DeviceState _currentState = EnumHelper.DeviceState.DSUninit;
|
||||
public EnumHelper.DeviceState CurrentState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentState;
|
||||
}
|
||||
set
|
||||
{
|
||||
_currentState = value;
|
||||
|
||||
if (value != EnumHelper.DeviceState.TBD)
|
||||
{
|
||||
OnDeviceStateChanged?.Invoke(this, _currentState);
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState"));
|
||||
}
|
||||
else
|
||||
{
|
||||
initialState = _currentState;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 设备标识符 从数据库获取
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备名称 从数据库获取
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
private IInitialConfig initialConfig = null;
|
||||
/// <summary>
|
||||
/// 设备初始化配置 从数据库获取
|
||||
/// </summary>
|
||||
public virtual IInitialConfig InitialConfig
|
||||
{
|
||||
get => initialConfig;
|
||||
set
|
||||
{
|
||||
initialConfig = value;
|
||||
this.Id = initialConfig.Id;
|
||||
this.Name = initialConfig.Name;
|
||||
|
||||
LoggerHelper.LogPath = initialConfig.LogPath;
|
||||
LoggerHelper.LogPrefix = initialConfig.Name;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public DeviceBase()
|
||||
{
|
||||
stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
|
||||
#region 设备抽象方法
|
||||
protected abstract void Init();
|
||||
|
||||
protected abstract void Pause();
|
||||
|
||||
protected abstract void Resume();
|
||||
|
||||
protected abstract void Start();
|
||||
|
||||
protected abstract void Stop();
|
||||
|
||||
public abstract void AttachToProcess(IProcess process);
|
||||
#endregion
|
||||
|
||||
#region IDispose
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
[DeviceExceptionAspect]
|
||||
public void StateChange(EnumHelper.DeviceState stateToBe)
|
||||
{
|
||||
if (CurrentState == stateToBe)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stateToBe.CheckPreStateValid((int)CurrentStateToBe))
|
||||
{
|
||||
string currentStateStr = CurrentStateToBe.GetEnumDescription();
|
||||
string stateToBeStr = stateToBe.GetEnumDescription();
|
||||
throw new ProcessException($"{InitialConfig.Name}设备的当前状态为{currentStateStr},无法切换至{stateToBeStr}");
|
||||
}
|
||||
|
||||
CurrentState = EnumHelper.DeviceState.TBD;
|
||||
CurrentStateToBe = stateToBe;
|
||||
}
|
||||
|
||||
[DeviceExceptionAspect]
|
||||
private void OnStateChanged(EnumHelper.DeviceState initialState)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CurrentStateToBe != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CurrentState == EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ProcessException($"{InitialConfig.Name}设备操作超时");
|
||||
}
|
||||
}
|
||||
|
||||
if (RetryTime >= 0)
|
||||
{
|
||||
if (initialState == CurrentStateToBe)
|
||||
{
|
||||
CurrentState = CurrentStateToBe;
|
||||
return;
|
||||
}
|
||||
|
||||
#region 状态切换操作
|
||||
switch (CurrentStateToBe)
|
||||
{
|
||||
case EnumHelper.DeviceState.DSInit:
|
||||
if (initialState == EnumHelper.DeviceState.DSOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Init();
|
||||
}
|
||||
break;
|
||||
case EnumHelper.DeviceState.DSOpen:
|
||||
if (initialState == EnumHelper.DeviceState.DSInit)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
else if (initialState == EnumHelper.DeviceState.DSPause)
|
||||
{
|
||||
Resume();
|
||||
pauseHandle.Set();
|
||||
}
|
||||
break;
|
||||
case EnumHelper.DeviceState.DSPause:
|
||||
pauseHandle.Reset();
|
||||
Pause();
|
||||
break;
|
||||
case EnumHelper.DeviceState.DSClose:
|
||||
if (initialState != DeviceState.DSUninit)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
RetryTime = 3;
|
||||
CurrentState = CurrentStateToBe;
|
||||
#endregion
|
||||
}
|
||||
|
||||
stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RetryTime--;
|
||||
if (RetryTime > 0)
|
||||
{
|
||||
OnStateChanged(initialState);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
throw new ProcessException($"设备{InitialConfig.Name}的{CurrentStateToBe.GetEnumDescription()}操作重复3次失败", ex, ExceptionLevel.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckDeviceOpTimeOut(object state)
|
||||
{
|
||||
stateChangedTimer?.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
if (CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
StateChange(EnumHelper.DeviceState.DSExcept);
|
||||
}
|
||||
}
|
||||
|
||||
#region 日志处理
|
||||
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
||||
public virtual void LogAsync(DateTime dt, string prefix, string msg)
|
||||
{
|
||||
OnLog?.BeginInvoke(dt, this, prefix + "\t" + msg, null, null);
|
||||
|
||||
if (InitialConfig.IsEnableLog)
|
||||
{
|
||||
LoggerHelper.LogAsync(dt, prefix, msg);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
144
src/BRS.Common.Model/Base/DeviceConfigBase.cs
Normal file
144
src/BRS.Common.Model/Base/DeviceConfigBase.cs
Normal file
@ -0,0 +1,144 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BRS.Common.Base
|
||||
{
|
||||
public class OperationConfigBase : IOperationConfig//, ISourceDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// 输入参数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Category("输入配置")]
|
||||
[Description("输入参数配置")]
|
||||
[DisplayName("输入参数")]
|
||||
[TypeConverter(typeof(SimpleCollectionConvert<int>))]
|
||||
public virtual List<int> InputPara { get; set; } = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// 异常反馈值
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("异常反馈值")]
|
||||
[DisplayName("异常反馈值")]
|
||||
public virtual int ExceptionValue { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 发生异常时的重新尝试次数
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("发生异常时的重新尝试次数")]
|
||||
[DisplayName("重试次数")]
|
||||
public virtual int ReTryTimes { get; set; } = 3;
|
||||
|
||||
[Browsable(false)]
|
||||
public string MonitorSetId { get; set; } = "";
|
||||
|
||||
[Browsable(false)]
|
||||
[JsonIgnore]
|
||||
public virtual string ExecuteDeviceId { get; set; } = "";
|
||||
|
||||
//[Browsable(false)]
|
||||
//[JsonIgnore]
|
||||
//public virtual string SourceDeviceId { get; set; } = "";
|
||||
|
||||
[Browsable(false)]
|
||||
[JsonIgnore]
|
||||
public virtual string OutputData { get; set; } = "";
|
||||
|
||||
[Browsable(false)]
|
||||
[JsonIgnore]
|
||||
public virtual int TriggerValue { get; set; }
|
||||
}
|
||||
|
||||
public class InitialConfigBase : IInitialConfig
|
||||
{
|
||||
[Category("通用配置")]
|
||||
[Description("设备索引")]
|
||||
[ReadOnly(true)]
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
[Category("通用配置")]
|
||||
[Description("设备名称")]
|
||||
[DisplayName("设备名称")]
|
||||
public string Name { get; set; } = "UnNamed";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设备是否启用
|
||||
/// </summary>
|
||||
[Category("通用配置")]
|
||||
[Description("设备是否启用")]
|
||||
[DisplayName("启用状态")]
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
|
||||
|
||||
protected string driverType = "";
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设备类型
|
||||
/// </summary>
|
||||
[Category("驱动类型")]
|
||||
[Description("设备驱动类型")]
|
||||
[DisplayName("驱动类型")]
|
||||
[TypeConverter(typeof(DeviceTypeSelectorConverter<IDevice>))]
|
||||
public virtual string DriverType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(driverType))
|
||||
{
|
||||
var attr = GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
driverType = attr.TypeCode;
|
||||
}
|
||||
}
|
||||
|
||||
return driverType;
|
||||
}
|
||||
set => driverType = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Category("日志配置")]
|
||||
[Description("日志记录目录")]
|
||||
[DisplayName("日志目录")]
|
||||
[Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))]
|
||||
public string LogPath { get; set; } = "";
|
||||
|
||||
[Category("日志配置")]
|
||||
[Description("true:启用日志记录 false:不启用日志记录")]
|
||||
[DisplayName("日志状态")]
|
||||
public virtual bool IsEnableLog { get; set; } = false;
|
||||
|
||||
[Category("日志配置")]
|
||||
[Description("true:启用CSV记录 false:不启用CSV记录")]
|
||||
[DisplayName("CSV状态")]
|
||||
public virtual bool IsEnableCSV { get; set; } = false;
|
||||
|
||||
public virtual List<string> GetHalconToolPathList()
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
//public InitialConfigBase()
|
||||
//{
|
||||
// var attr = this.GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// this.DriverType = attr.TypeCode;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
190
src/BRS.Common.Model/Base/InputConfigBase.cs
Normal file
190
src/BRS.Common.Model/Base/InputConfigBase.cs
Normal file
@ -0,0 +1,190 @@
|
||||
using Bro.Common.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Bro.Common.Base
|
||||
{
|
||||
public class InputConfigBase : IInputConfig
|
||||
{
|
||||
//public InputConfigBase()
|
||||
//{
|
||||
// StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
//}
|
||||
|
||||
//[JsonIgnore]
|
||||
//public AutoResetEvent InputHanlder { get; set; } = new AutoResetEvent(false);
|
||||
|
||||
// [JsonIgnore]
|
||||
//public string IConfigId = Guid.NewGuid().ToString();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public Dictionary<string, AutoResetEvent> InputHanlderDict { get; set; } = new Dictionary<string, AutoResetEvent>();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public Dictionary<string, bool> InputFlagDict { get; set; } = new Dictionary<string, bool>();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public ConcurrentDictionary<string, AutoResetEvent> InputHanlderDict { get; set; } = new ConcurrentDictionary<string, AutoResetEvent>();
|
||||
|
||||
//[JsonIgnore]
|
||||
//public ConcurrentDictionary<string, bool> InputFlagDict { get; set; } = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
[JsonIgnore]
|
||||
public bool BoundFlag { get; set; } = false;
|
||||
|
||||
public bool IsInputNeed { get; set; } = false;
|
||||
|
||||
public string InputMethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 第三方设备输入参数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public dynamic InputPara { get; set; }
|
||||
|
||||
private string processId;
|
||||
[JsonIgnore]
|
||||
public string ProcessId
|
||||
{
|
||||
get
|
||||
{
|
||||
return processId;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (processId != value)
|
||||
{
|
||||
//仅在工序编号赋值后建立消息连接
|
||||
processId = value;
|
||||
|
||||
//if (conn == null)
|
||||
//{
|
||||
// conn = new HubConnection(GlobalVar.SignalRServer);
|
||||
|
||||
// proxy = conn.CreateHubProxy("DeviceHub");
|
||||
// proxy.On<InputPara>("OnDeviceInput", OnDeviceInput);
|
||||
|
||||
// conn.Start().Wait();
|
||||
//}
|
||||
//lock (this)
|
||||
{
|
||||
//InputHanlderDict[processId] = new AutoResetEvent(false);
|
||||
//InputFlagDict[processId] = false;
|
||||
//InputHanlderDict.AddOrUpdate(processId, new AutoResetEvent(false), (a, b) => { return new AutoResetEvent(false); });
|
||||
//InputFlagDict.AddOrUpdate(processId, false, (a, b) => { return false; });
|
||||
|
||||
InputHandle = new AutoResetEvent(false);
|
||||
//StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
}
|
||||
|
||||
//if (StateMachine.OnDeviceInput != null)
|
||||
//{
|
||||
// var list = StateMachine.OnDeviceInput.GetInvocationList().ToList();
|
||||
// if (list != null)
|
||||
// {
|
||||
// if (!list.Any(d =>
|
||||
// {
|
||||
// InputConfigBase icb = d.Target as InputConfigBase;
|
||||
// return icb.ProcessId == ProcessId;
|
||||
// }))
|
||||
// {
|
||||
// StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
//StateMachine.OnDeviceInput += OnDeviceInput;
|
||||
//PubSubCenter.GetInstance().Subscribe(processId, OnDeviceInput);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public AutoResetEvent InputHandle { get; set; } = new AutoResetEvent(false);
|
||||
|
||||
public string ProcessName { get; set; }
|
||||
|
||||
|
||||
|
||||
//HubConnection conn;
|
||||
//IHubProxy proxy;
|
||||
|
||||
/// <summary>
|
||||
/// 适用于第三方的信号输入
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
//private object OnDeviceInput(ISubscriber sub, object param1, object param2)
|
||||
private void OnDeviceInput(InputPara obj)
|
||||
{
|
||||
//Debug.WriteLine(DateTime.Now.ToString("mm:ss.fff") + "\t输入流程:" + obj.ProcessId + ";\t本流程编号:" + ProcessId);
|
||||
//输入参数必须有一个字段是ProcessId,保存工序编号
|
||||
//string processId = obj.ProcessId;
|
||||
|
||||
//if (obj.ProcessId == ProcessId)
|
||||
//{
|
||||
// InputPara = obj.ParaObj;
|
||||
// InputHanlderDict[].Set();
|
||||
// BoundFlag = false;
|
||||
//}
|
||||
|
||||
//InputPara obj = param1 as InputPara;
|
||||
|
||||
//lock (this)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (InputHanlderDict.Keys.Contains(obj.ProcessId))
|
||||
if (ProcessId == obj.ProcessId)
|
||||
{
|
||||
//Debug.WriteLine(DateTime.Now.ToString("mm:ss.fff") + "\t流程编号:" + obj.ProcessId);
|
||||
//InputHanlderDict[obj.ProcessId].Set();
|
||||
//InputFlagDict[obj.ProcessId] = true;
|
||||
InputHandle.Set();
|
||||
//InputHanlderDict.Remove(obj.ProcessId);
|
||||
//StateMachine.OnDeviceInput -= OnDeviceInput;
|
||||
//PubSubCenter.GetInstance().RemoveSubscriber(ProcessId, OnDeviceInput);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
//return null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
//foreach (var handle in InputHanlderDict)
|
||||
//{
|
||||
// handle.Value.Set();
|
||||
//}
|
||||
|
||||
//StateMachine.OnDeviceInput -= OnDeviceInput;
|
||||
|
||||
//InputHanlderDict = new ConcurrentDictionary<string, AutoResetEvent>();
|
||||
//InputFlagDict = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
//GC.Collect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class InputPara : IProcessID
|
||||
{
|
||||
public string ProcessId { get; set; }
|
||||
|
||||
//[DataMember]
|
||||
public dynamic ParaObj { get; set; }
|
||||
|
||||
public string ProcessName { get; set; }
|
||||
}
|
||||
}
|
85
src/BRS.Common.Model/Base/OperationConfigBase.cs
Normal file
85
src/BRS.Common.Model/Base/OperationConfigBase.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using Bro.Common.Helper;
|
||||
using Bro.Common.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Bro.Common.Helper.EnumHelper;
|
||||
|
||||
namespace Bro.Common.Base
|
||||
{
|
||||
//[Device("Base", "基础操作配置", EnumHelper.DeviceAttributeType.OperationConfig)]
|
||||
public class OperationConfigBase : IOperationConfig
|
||||
{
|
||||
////[JsonIgnore]
|
||||
//public IDeviceConfig DeviceConfig { get; set; }
|
||||
|
||||
////[JsonIgnore]
|
||||
//public IInputConfig InputConfig { get; set; }
|
||||
|
||||
//public string OutputMethodName { get; set; }
|
||||
|
||||
////[JsonIgnore]
|
||||
//public string ProcessId { get; set; }
|
||||
|
||||
//public string ProcessName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public virtual int ResultOutput { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 输入参数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public List<int> InputPara { get; set; }
|
||||
|
||||
|
||||
[Category("启用配置")]
|
||||
[Description("true:启用该配置执行操作;false:不启用该配置,不执行操作")]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 异常反馈值
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("异常反馈值")]
|
||||
public int ExceptionValue { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 发生异常时的重新尝试次数
|
||||
/// </summary>
|
||||
[Category("异常反馈设置")]
|
||||
[Description("发生异常时的重新尝试次数")]
|
||||
public int ReTryTimes { get; set; } = 3;
|
||||
|
||||
///// <summary>
|
||||
///// 发生异常多次后向PLC报警
|
||||
///// </summary>
|
||||
//[Category("异常反馈设置")]
|
||||
//[Description("发生异常多次后向PLC报警")]
|
||||
//public int PLCWarningTimes { get; set; } = 0;
|
||||
|
||||
///// <summary>
|
||||
///// 向PLC报警的报警类别
|
||||
///// </summary>
|
||||
//[Category("异常反馈设置")]
|
||||
//[Description("向PLC报警的报警类别")]
|
||||
//public WarningFromPC WarningType { get; set; } = WarningFromPC.UnknowError;
|
||||
|
||||
///// <summary>
|
||||
///// 14 (2+4+8)表示全部采用上道工序输出配置
|
||||
///// </summary>
|
||||
//public int ConfigPreset { get; set; } = 0;
|
||||
}
|
||||
|
||||
public class OperationConfigCommon : OperationConfigBase
|
||||
{
|
||||
[ConfigOutputResource("OutputResultCommon")]
|
||||
public override int ResultOutput { get; set; }
|
||||
}
|
||||
}
|
39
src/BRS.Common.Model/Base/ProcessBase.cs
Normal file
39
src/BRS.Common.Model/Base/ProcessBase.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using Bro.Device.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Bro.Device.Common.Helper;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Common.Base
|
||||
{
|
||||
public class ProcessBase : IProcess
|
||||
{
|
||||
private EnumHelper.ProcessState _currentState = EnumHelper.ProcessState.Idel;
|
||||
|
||||
[NotMapped]
|
||||
public EnumHelper.ProcessState CurrentState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentState;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _currentState)
|
||||
{
|
||||
_currentState = value;
|
||||
OnStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnStateChanged()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
63
src/BRS.Common.Model/Exception/ExceptionHelper.cs
Normal file
63
src/BRS.Common.Model/Exception/ExceptionHelper.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public enum ExceptionLevel
|
||||
{
|
||||
Info = 0,
|
||||
Warning = 1,
|
||||
Fatal = 2,
|
||||
}
|
||||
|
||||
//public delegate void OnProcessExceptionRaisedDelegate(DateTime dt, ProcessException ex);
|
||||
//[Serializable]
|
||||
public class ProcessException : Exception
|
||||
{
|
||||
public ExceptionLevel Level { get; set; } = ExceptionLevel.Warning;
|
||||
|
||||
public ProcessException()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcessException(Exception ex, ExceptionLevel lvl = ExceptionLevel.Warning) : base(ex.Message, ex)
|
||||
{
|
||||
Level = lvl;
|
||||
ExceptionNotice();
|
||||
}
|
||||
|
||||
public ProcessException(string error, Exception ex = null, ExceptionLevel lvl = ExceptionLevel.Warning) : base(error, ex)
|
||||
{
|
||||
Level = lvl;
|
||||
ExceptionNotice();
|
||||
}
|
||||
|
||||
public void ExceptionNotice()
|
||||
{
|
||||
//OnProcessExceptionRaised?.Invoke(DateTime.Now, this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExceptionHelper
|
||||
{
|
||||
public static LogLevel LogLevel = LogLevel.Information;
|
||||
public static string GetExceptionMessage(this Exception ex)
|
||||
{
|
||||
string msg = "异常信息:" + ex.Message;
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
msg += ";\t内部异常信息:" + ex.InnerException.GetExceptionMessage();
|
||||
}
|
||||
|
||||
if (LogLevel <= LogLevel.Assist)
|
||||
{
|
||||
msg += (";\r\n\t\tStackTrace:" + ex.StackTrace);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthorityException : ProcessException
|
||||
{
|
||||
}
|
||||
}
|
9
src/BRS.Common.Model/Exception/IExceptionHandler.cs
Normal file
9
src/BRS.Common.Model/Exception/IExceptionHandler.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IExceptionHandler
|
||||
{
|
||||
Action<DateTime, Exception> OnExceptionOccured { get; set; }
|
||||
}
|
||||
}
|
53
src/BRS.Common.Model/Factory/ConfigFactory.cs
Normal file
53
src/BRS.Common.Model/Factory/ConfigFactory.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using BRS.Common.Base;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Factory
|
||||
{
|
||||
public static class ConfigFactory
|
||||
{
|
||||
public static IOperationConfig GetOperationConfig(string typeName)
|
||||
{
|
||||
Type configType = FactoryHelper.GetTypeByAtrributeTypeName(typeName, DeviceAttributeType.OperationConfig);
|
||||
|
||||
if (configType == null)
|
||||
{
|
||||
return new OperationConfigBase();
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(configType) as IOperationConfig;
|
||||
}
|
||||
|
||||
public static IInitialConfig GetInitialConfig(string typeName)
|
||||
{
|
||||
Type configType = FactoryHelper.GetTypeByAtrributeTypeName(typeName, DeviceAttributeType.InitialConfig);
|
||||
|
||||
if (configType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(configType) as IInitialConfig;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Type> GetAllOpConfigTypes()
|
||||
{
|
||||
Dictionary<string, Type> opConfigTypeDict = new Dictionary<string, Type>();
|
||||
FactoryHelper.TYPES.ForEach(t =>
|
||||
{
|
||||
var attr = t.GetCustomAttribute<DeviceAttribute>();
|
||||
|
||||
if (attr != null && attr.AttrType == DeviceAttributeType.OperationConfig)
|
||||
{
|
||||
opConfigTypeDict[attr.TypeCode] = t;
|
||||
}
|
||||
});
|
||||
|
||||
return opConfigTypeDict;
|
||||
}
|
||||
}
|
||||
}
|
105
src/BRS.Common.Model/Factory/DeviceFactory.cs
Normal file
105
src/BRS.Common.Model/Factory/DeviceFactory.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Factory
|
||||
{
|
||||
public static class DeviceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据设备类型名称获取设备对象
|
||||
/// </summary>
|
||||
/// <param name="deviceTypeName">设备类型名称,如HalconCamera</param>
|
||||
/// <returns></returns>
|
||||
//public static IDevice GetDeviceInstanceByTypeName(string deviceTypeName)
|
||||
//{
|
||||
// Type deviceType = FactoryHelper.GetTypeByAtrributeTypeName(deviceTypeName, DeviceAttributeType.Device);
|
||||
|
||||
// if (deviceType == null)
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// return Activator.CreateInstance(deviceType) as IDevice;
|
||||
//}
|
||||
|
||||
public static IDevice GetDeviceInstanceByTypeName(string deviceTypeName)
|
||||
{
|
||||
Type deviceType = FactoryHelper.GetTypeByAtrributeTypeName(deviceTypeName, DeviceAttributeType.Device);
|
||||
|
||||
if (deviceType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(deviceType) as IDevice;
|
||||
}
|
||||
|
||||
public static T GetDeviceInstanceByTypeName<T>(string deviceTypeName) where T : class, IDevice
|
||||
{
|
||||
Type deviceType = FactoryHelper.GetTypeByAtrributeTypeName(deviceTypeName, DeviceAttributeType.Device);
|
||||
|
||||
if (deviceType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(deviceType) as T;
|
||||
}
|
||||
|
||||
public static List<DeviceAttribute> GetAllSupportDeviceTypeAttr(Type instanceBase = null)
|
||||
{
|
||||
List<DeviceAttribute> deviceAttrs = new List<DeviceAttribute>();
|
||||
FactoryHelper.TYPES.ForEach(t =>
|
||||
{
|
||||
var attr = t.GetCustomAttribute<DeviceAttribute>();
|
||||
|
||||
if (attr.AttrType == DeviceAttributeType.Device)
|
||||
{
|
||||
if (instanceBase != null)
|
||||
{
|
||||
if (instanceBase.IsInterface || t.IsSubclassOf(instanceBase))
|
||||
{
|
||||
deviceAttrs.Add(attr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
deviceAttrs.Add(attr);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return deviceAttrs;
|
||||
}
|
||||
|
||||
public static List<string> GetAllSupportDeviceTypeNames(Type instanceBase = null)
|
||||
{
|
||||
List<string> deviceNames = new List<string>();
|
||||
FactoryHelper.TYPES.ForEach(t =>
|
||||
{
|
||||
var attr = t.GetCustomAttribute<DeviceAttribute>();
|
||||
|
||||
if (attr.AttrType == DeviceAttributeType.Device)
|
||||
{
|
||||
if (instanceBase != null)
|
||||
{
|
||||
if (t.IsSubclassOf(instanceBase))
|
||||
{
|
||||
deviceNames.Add(attr.TypeCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
deviceNames.Add(attr.TypeCode);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return deviceNames;
|
||||
}
|
||||
}
|
||||
}
|
46
src/BRS.Common.Model/Factory/ElementFactory.cs
Normal file
46
src/BRS.Common.Model/Factory/ElementFactory.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BRS.Common.Factory
|
||||
{
|
||||
public static class ElementFactory
|
||||
{
|
||||
public static Dictionary<ElementAttribute, Type> GetAllElementsInfo()
|
||||
{
|
||||
//Dictionary<ElementAttribute, Type> dict = new Dictionary<ElementAttribute, Type>();
|
||||
//List<string> eleDlls = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).GetFiles("BRS.Element.*.dll").Select(u => u.FullName).ToList();
|
||||
|
||||
//eleDlls.ForEach(dll =>
|
||||
//{
|
||||
// Assembly assm = Assembly.LoadFile(dll);
|
||||
// assm.GetTypes().ToList().ForEach(u =>
|
||||
// {
|
||||
// var attr = u.GetCustomAttribute<ElementAttribute>();
|
||||
|
||||
// if (attr != null)
|
||||
// {
|
||||
// dict[attr] = u;
|
||||
// }
|
||||
// });
|
||||
//});
|
||||
|
||||
//Assembly.GetExecutingAssembly().GetTypes().ToList().ForEach(u =>
|
||||
//{
|
||||
// var attr = u.GetCustomAttribute<ElementAttribute>();
|
||||
|
||||
// if (attr != null)
|
||||
// {
|
||||
// dict[attr] = u;
|
||||
// }
|
||||
//});
|
||||
|
||||
//return dict;
|
||||
|
||||
return FactoryHelper.GetAttributeType<ElementAttribute>();
|
||||
}
|
||||
}
|
||||
}
|
119
src/BRS.Common.Model/Factory/FactoryHelper.cs
Normal file
119
src/BRS.Common.Model/Factory/FactoryHelper.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BRS.Common.Factory
|
||||
{
|
||||
public static class FactoryHelper
|
||||
{
|
||||
const string DLLPATTERN = "BRS.*.dll";
|
||||
|
||||
|
||||
private static readonly string[] DLLPATTERNS = { "BRS.", "XKRS." };
|
||||
|
||||
|
||||
private static List<Type> types = new List<Type>();
|
||||
public static List<Type> TYPES
|
||||
{
|
||||
get
|
||||
{
|
||||
if (types.Count <= 0)
|
||||
{
|
||||
types = GetAttributeType<DeviceAttribute>().Values.ToList();
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<T, Type> GetAttributeType<T>() where T : Attribute
|
||||
{
|
||||
Dictionary<T, Type> attrTypeDict = new Dictionary<T, Type>();
|
||||
|
||||
//var dllFiles = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).GetFiles(DLLPATTERN).Select(u => u.FullName).ToList();
|
||||
|
||||
var dllFiles = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory)
|
||||
.GetFiles("*.dll")
|
||||
.Where(fi => DLLPATTERNS.Any(pattern => fi.Name.StartsWith(pattern)))
|
||||
.Select(u =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return u.FullName;
|
||||
}
|
||||
catch { }
|
||||
return string.Empty;
|
||||
})
|
||||
.Where(s => !string.IsNullOrEmpty(s))
|
||||
.ToList();
|
||||
|
||||
|
||||
dllFiles.ForEach(f =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly assm = Assembly.LoadFrom(f);
|
||||
if (assm != null)
|
||||
{
|
||||
assm.GetTypes().ToList().ForEach(t =>
|
||||
{
|
||||
T attr = t.GetCustomAttribute<T>();
|
||||
|
||||
if (attr != null)
|
||||
{
|
||||
attrTypeDict[attr] = t;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
return attrTypeDict;
|
||||
}
|
||||
|
||||
//private static Dictionary<string, Type> device_dict = new Dictionary<string, Type>();
|
||||
//public static Dictionary<string, Type> DEVICE_DICT
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (device_dict.Count < 0)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// return device_dict;
|
||||
// }
|
||||
//}
|
||||
|
||||
//private static List<string> device_type_names = new List<string>();
|
||||
//public static List<string> DEVICE_TYPE_NAMES
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (device_type_names.Count < 0)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// return device_type_names;
|
||||
// }
|
||||
//}
|
||||
|
||||
public static Type GetTypeByAtrributeTypeName(string attrTypeName, EnumHelper.DeviceAttributeType attrType)
|
||||
{
|
||||
Type type = TYPES.FirstOrDefault(t =>
|
||||
{
|
||||
DeviceAttribute attr = t.GetCustomAttribute<DeviceAttribute>();
|
||||
return attr != null && attr.TypeCode == attrTypeName && attr.AttrType == attrType;
|
||||
});
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
86
src/BRS.Common.Model/Factory/ProcessFactory.cs
Normal file
86
src/BRS.Common.Model/Factory/ProcessFactory.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BRS.Common.Factory
|
||||
{
|
||||
public static class ProcessFactory
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取项目中所有流程,即寻找所有带有 [Process] 属性的
|
||||
/// </summary>
|
||||
/// <returns>返回流程名称列表</returns>
|
||||
public static List<string> GetProcessCodes()
|
||||
{
|
||||
var attrs = FactoryHelper.GetAttributeType<ProcessAttribute>().Keys;
|
||||
List<string> processCodes = attrs.Select(u => u.ProcessCode).Distinct().ToList();
|
||||
|
||||
return processCodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取StationProcess
|
||||
/// </summary>
|
||||
/// <param name="processCode">流程代码</param>
|
||||
/// <param name="msg">异常信息</param>
|
||||
/// <returns></returns>
|
||||
public static IProcess CreateStationProcess(string processCode, string productionCode, out string msg)
|
||||
{
|
||||
IProcess proc = null;
|
||||
msg = "";
|
||||
|
||||
try
|
||||
{
|
||||
var typeDict = FactoryHelper.GetAttributeType<ProcessAttribute>();
|
||||
foreach (KeyValuePair<ProcessAttribute, Type> pair in typeDict)
|
||||
{
|
||||
if (typeof(IProcess).IsAssignableFrom(pair.Value) && pair.Key.ProcessCode == processCode)
|
||||
{
|
||||
proc = Activator.CreateInstance(pair.Value, productionCode) as IProcess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.GetExceptionMessage();
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取StationConfig
|
||||
/// </summary>
|
||||
/// <param name="processCode">流程代码</param>
|
||||
/// <param name="msg">异常信息</param>
|
||||
/// <returns></returns>
|
||||
public static IProcessConfig CreateStationConfig(string processCode, out string msg)
|
||||
{
|
||||
IProcessConfig config = null;
|
||||
msg = "";
|
||||
|
||||
try
|
||||
{
|
||||
var typeDict = FactoryHelper.GetAttributeType<ProcessAttribute>();
|
||||
foreach (KeyValuePair<ProcessAttribute, Type> pair in typeDict)
|
||||
{
|
||||
if (typeof(IProcessConfig).IsAssignableFrom(pair.Value) && pair.Key.ProcessCode == processCode)
|
||||
{
|
||||
config = Activator.CreateInstance(pair.Value) as IProcessConfig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.GetExceptionMessage();
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
31
src/BRS.Common.Model/Factory/UIFactory.cs
Normal file
31
src/BRS.Common.Model/Factory/UIFactory.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using BRS.Common.Interface;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BRS.Common.Factory
|
||||
{
|
||||
public class UIFactory
|
||||
{
|
||||
public static IRunCtrl GetRunCtrl(IDevice device)
|
||||
{
|
||||
var attr = device.GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
if (attr == null)
|
||||
return null;
|
||||
|
||||
var type = FactoryHelper.GetTypeByAtrributeTypeName(attr.TypeCode, EnumHelper.DeviceAttributeType.RunCtrl);
|
||||
if (type == null)
|
||||
return null;
|
||||
|
||||
IRunCtrl runCtrl = Activator.CreateInstance(type, new object[] { device }) as IRunCtrl;
|
||||
return runCtrl;
|
||||
}
|
||||
|
||||
public static bool IsDeviceCtrlExisted(string typeName, EnumHelper.DeviceAttributeType ctrlType)
|
||||
{
|
||||
var type = FactoryHelper.GetTypeByAtrributeTypeName(typeName, ctrlType);
|
||||
|
||||
return type != null;
|
||||
}
|
||||
}
|
||||
}
|
119
src/BRS.Common.Model/Forms/FrmDeviceOpConfigEditor.Designer.cs
generated
Normal file
119
src/BRS.Common.Model/Forms/FrmDeviceOpConfigEditor.Designer.cs
generated
Normal file
@ -0,0 +1,119 @@
|
||||
namespace BRS.Common.Model.Forms
|
||||
{
|
||||
partial class FrmDeviceOpConfigEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnReset = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.btnConfirm = new System.Windows.Forms.Button();
|
||||
this.propGrid = new System.Windows.Forms.PropertyGrid();
|
||||
this.cboDevice = new System.Windows.Forms.ComboBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnReset
|
||||
//
|
||||
this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnReset.BackColor = System.Drawing.Color.Red;
|
||||
this.btnReset.ForeColor = System.Drawing.Color.White;
|
||||
this.btnReset.Location = new System.Drawing.Point(206, 14);
|
||||
this.btnReset.Name = "btnReset";
|
||||
this.btnReset.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnReset.TabIndex = 4;
|
||||
this.btnReset.Text = "重置配置";
|
||||
this.btnReset.UseVisualStyleBackColor = false;
|
||||
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.Location = new System.Drawing.Point(287, 14);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 5;
|
||||
this.btnCancel.Text = "取消";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// btnConfirm
|
||||
//
|
||||
this.btnConfirm.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnConfirm.Location = new System.Drawing.Point(368, 14);
|
||||
this.btnConfirm.Name = "btnConfirm";
|
||||
this.btnConfirm.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnConfirm.TabIndex = 6;
|
||||
this.btnConfirm.Text = "确认";
|
||||
this.btnConfirm.UseVisualStyleBackColor = true;
|
||||
this.btnConfirm.Click += new System.EventHandler(this.btnConfirm_Click);
|
||||
//
|
||||
// propGrid
|
||||
//
|
||||
this.propGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.propGrid.Location = new System.Drawing.Point(3, 56);
|
||||
this.propGrid.Name = "propGrid";
|
||||
this.propGrid.Size = new System.Drawing.Size(450, 346);
|
||||
this.propGrid.TabIndex = 3;
|
||||
this.propGrid.ToolbarVisible = false;
|
||||
//
|
||||
// cboDevice
|
||||
//
|
||||
this.cboDevice.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cboDevice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cboDevice.FormattingEnabled = true;
|
||||
this.cboDevice.Location = new System.Drawing.Point(12, 16);
|
||||
this.cboDevice.Name = "cboDevice";
|
||||
this.cboDevice.Size = new System.Drawing.Size(165, 20);
|
||||
this.cboDevice.TabIndex = 7;
|
||||
//
|
||||
// FrmDeviceOpConfigEditor
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(455, 404);
|
||||
this.Controls.Add(this.cboDevice);
|
||||
this.Controls.Add(this.btnReset);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnConfirm);
|
||||
this.Controls.Add(this.propGrid);
|
||||
this.Name = "FrmDeviceOpConfigEditor";
|
||||
this.ShowIcon = false;
|
||||
this.Text = "操作设备及配置编辑界面";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.Button btnReset;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.Button btnConfirm;
|
||||
private System.Windows.Forms.PropertyGrid propGrid;
|
||||
private System.Windows.Forms.ComboBox cboDevice;
|
||||
}
|
||||
}
|
170
src/BRS.Common.Model/Forms/FrmDeviceOpConfigEditor.cs
Normal file
170
src/BRS.Common.Model/Forms/FrmDeviceOpConfigEditor.cs
Normal file
@ -0,0 +1,170 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Base;
|
||||
using BRS.Common.Factory;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BRS.Common.Model.Forms
|
||||
{
|
||||
public partial class FrmDeviceOpConfigEditor : Form
|
||||
{
|
||||
public FrmDeviceOpConfigEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
//private DeviceOpBind bind = null;
|
||||
public DeviceOpBind Bind { get; set; }
|
||||
|
||||
IOperationConfig backOpConfig = new OperationConfigBase();
|
||||
List<IDevice> deviceList = null;
|
||||
IDevice currentDevice = null;
|
||||
|
||||
string MethodOpType = null;
|
||||
public FrmDeviceOpConfigEditor(DeviceOpBind bind, string methodOpType = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
InitialDeviceCbo();
|
||||
|
||||
Bind = bind;
|
||||
if (!string.IsNullOrWhiteSpace(bind.Device))
|
||||
{
|
||||
cboDevice.SelectedValue = bind.Device;
|
||||
|
||||
currentDevice = deviceList.FirstOrDefault(u => u.Id == bind.Device);
|
||||
if (currentDevice != null)
|
||||
{
|
||||
var attr = currentDevice.GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
backOpConfig = ConfigFactory.GetOperationConfig(attr.TypeCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cboDevice.Items.Count > 0)
|
||||
cboDevice.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
if (methodOpType == null)
|
||||
{
|
||||
cboDevice.Enabled = true;
|
||||
cboDevice.SelectedIndexChanged += CboDevice_SelectedIndexChanged;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cboDevice.Enabled = false;
|
||||
MethodOpType = methodOpType;
|
||||
}
|
||||
|
||||
if (bind.OpConfig == null)
|
||||
{
|
||||
bind.OpConfig = new OperationConfigBase();
|
||||
|
||||
if (currentDevice != null)
|
||||
{
|
||||
var attr = currentDevice.GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
if (attr != null)
|
||||
bind.OpConfig = ConfigFactory.GetOperationConfig(attr.TypeCode);
|
||||
}
|
||||
}
|
||||
|
||||
bind.OpConfig.ExecuteDeviceId = bind.Device;
|
||||
|
||||
backOpConfig.DataFrom(bind.OpConfig);
|
||||
|
||||
propGrid.SelectedObject = bind.OpConfig;
|
||||
|
||||
}
|
||||
|
||||
private void CboDevice_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
ChangeOpConfigByDevice();
|
||||
}
|
||||
|
||||
private void ChangeOpConfigByDevice()
|
||||
{
|
||||
var device = deviceList.FirstOrDefault(u => u.Id == cboDevice.SelectedValue.ToString());
|
||||
if (device != null)
|
||||
{
|
||||
var attr = device.GetType().GetCustomAttribute<DeviceAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
var opConfig = ConfigFactory.GetOperationConfig(attr.TypeCode);
|
||||
opConfig.ExecuteDeviceId = device.Id;
|
||||
propGrid.SelectedObject = opConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitialDeviceCbo()
|
||||
{
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
deviceList = scope.Resolve<List<IDevice>>();
|
||||
var iDeviceList = new List<ISimpleDevice>(deviceList);
|
||||
iDeviceList.Insert(0, new SimpleDevice { Name = "未指定", Id = "" });
|
||||
if (deviceList.Count > 0)
|
||||
{
|
||||
UIHelper.SetCombo(cboDevice, iDeviceList, "Name", "Id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
Bind.OpConfig = backOpConfig;
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
}
|
||||
|
||||
private void btnConfirm_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (propGrid.SelectedObject != null)
|
||||
{
|
||||
Bind.Device = cboDevice.SelectedValue?.ToString();
|
||||
Bind.OpConfig = propGrid.SelectedObject as IOperationConfig;
|
||||
Bind.OpConfig.ExecuteDeviceId = Bind.Device;
|
||||
}
|
||||
else
|
||||
{
|
||||
Bind = null;
|
||||
}
|
||||
this.DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
private void btnReset_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MethodOpType == null)
|
||||
{
|
||||
ChangeOpConfigByDevice();
|
||||
}
|
||||
else
|
||||
{
|
||||
var device = deviceList.FirstOrDefault(u => u.Id == cboDevice.SelectedValue.ToString());
|
||||
if (device != null)
|
||||
{
|
||||
var opConfig = ConfigFactory.GetOperationConfig(MethodOpType);
|
||||
opConfig.ExecuteDeviceId = device.Id;
|
||||
propGrid.SelectedObject = opConfig;
|
||||
}
|
||||
else
|
||||
{
|
||||
propGrid.SelectedObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
src/BRS.Common.Model/Forms/FrmDeviceOpConfigEditor.resx
Normal file
120
src/BRS.Common.Model/Forms/FrmDeviceOpConfigEditor.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
120
src/BRS.Common.Model/Forms/FrmOpConfigEdit.Designer.cs
generated
Normal file
120
src/BRS.Common.Model/Forms/FrmOpConfigEdit.Designer.cs
generated
Normal file
@ -0,0 +1,120 @@
|
||||
namespace BRS.Common.Model.Forms
|
||||
{
|
||||
partial class FrmOpConfigEdit
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.propGrid = new System.Windows.Forms.PropertyGrid();
|
||||
this.btnConfirm = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.lblOpType = new System.Windows.Forms.Label();
|
||||
this.btnReset = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// propGrid
|
||||
//
|
||||
this.propGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.propGrid.Location = new System.Drawing.Point(4, 53);
|
||||
this.propGrid.Name = "propGrid";
|
||||
this.propGrid.Size = new System.Drawing.Size(509, 341);
|
||||
this.propGrid.TabIndex = 0;
|
||||
this.propGrid.ToolbarVisible = false;
|
||||
//
|
||||
// btnConfirm
|
||||
//
|
||||
this.btnConfirm.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnConfirm.Location = new System.Drawing.Point(429, 12);
|
||||
this.btnConfirm.Name = "btnConfirm";
|
||||
this.btnConfirm.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnConfirm.TabIndex = 1;
|
||||
this.btnConfirm.Text = "确认";
|
||||
this.btnConfirm.UseVisualStyleBackColor = true;
|
||||
this.btnConfirm.Click += new System.EventHandler(this.btnConfirm_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.Location = new System.Drawing.Point(348, 12);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 1;
|
||||
this.btnCancel.Text = "取消";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// lblOpType
|
||||
//
|
||||
this.lblOpType.AutoSize = true;
|
||||
this.lblOpType.Location = new System.Drawing.Point(13, 22);
|
||||
this.lblOpType.Name = "lblOpType";
|
||||
this.lblOpType.Size = new System.Drawing.Size(53, 12);
|
||||
this.lblOpType.TabIndex = 2;
|
||||
this.lblOpType.Text = " ";
|
||||
//
|
||||
// btnReset
|
||||
//
|
||||
this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnReset.BackColor = System.Drawing.Color.Red;
|
||||
this.btnReset.ForeColor = System.Drawing.Color.White;
|
||||
this.btnReset.Location = new System.Drawing.Point(267, 12);
|
||||
this.btnReset.Name = "btnReset";
|
||||
this.btnReset.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnReset.TabIndex = 1;
|
||||
this.btnReset.Text = "重置配置";
|
||||
this.btnReset.UseVisualStyleBackColor = false;
|
||||
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
|
||||
//
|
||||
// FrmOpConfigEdit
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(516, 397);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.lblOpType);
|
||||
this.Controls.Add(this.btnReset);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnConfirm);
|
||||
this.Controls.Add(this.propGrid);
|
||||
this.Name = "FrmOpConfigEdit";
|
||||
this.Text = "操作配置编辑界面";
|
||||
this.Load += new System.EventHandler(this.FrmOpConfigEdit_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.PropertyGrid propGrid;
|
||||
private System.Windows.Forms.Button btnConfirm;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.Label lblOpType;
|
||||
private System.Windows.Forms.Button btnReset;
|
||||
}
|
||||
}
|
102
src/BRS.Common.Model/Forms/FrmOpConfigEdit.cs
Normal file
102
src/BRS.Common.Model/Forms/FrmOpConfigEdit.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using Autofac;
|
||||
using BRS.Common.Factory;
|
||||
using BRS.Common.Model.Helper;
|
||||
using BRS.Common.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BRS.Common.Model.Forms
|
||||
{
|
||||
public partial class FrmOpConfigEdit : Form
|
||||
{
|
||||
public string MethodCode { get; set; }
|
||||
public IOperationConfig BackupConfig { get; set; }
|
||||
public IOperationConfig OpConfig { get; set; }
|
||||
|
||||
readonly string MonitorSetId = "";
|
||||
|
||||
public FrmOpConfigEdit()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public FrmOpConfigEdit(string methodCode, string monitorSetId, IOperationConfig opConfig)
|
||||
{
|
||||
InitializeComponent();
|
||||
lblOpType.Text = MethodCode = methodCode;
|
||||
|
||||
MonitorSetId = monitorSetId;
|
||||
|
||||
OpConfig = opConfig;
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetOperationConfigMonitorSetId(OpConfig);
|
||||
SetOperationConfigMonitorSetId(BackupConfig);
|
||||
DialogResult = DialogResult.Cancel;
|
||||
}
|
||||
|
||||
private void btnConfirm_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetOperationConfigMonitorSetId(OpConfig);
|
||||
SetOperationConfigMonitorSetId(BackupConfig);
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
private void SetOperationConfigMonitorSetId(IOperationConfig config)
|
||||
{
|
||||
if (config != null)
|
||||
{
|
||||
config.MonitorSetId = MonitorSetId;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnReset_Click(object sender, EventArgs e)
|
||||
{
|
||||
string opType = "";
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
List<ProcessMethodAttribute> methodList = scope.Resolve<List<ProcessMethodAttribute>>();
|
||||
var method = methodList.FirstOrDefault(u => u.MethodCode == MethodCode);
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
opType = method.DeviceType;
|
||||
BackupConfig = ConfigFactory.GetOperationConfig(opType);
|
||||
}
|
||||
}
|
||||
|
||||
propGrid.SelectedObject = OpConfig = ConfigFactory.GetOperationConfig(opType);
|
||||
}
|
||||
|
||||
private void FrmOpConfigEdit_Load(object sender, EventArgs e)
|
||||
{
|
||||
string opType = "";
|
||||
using (var scope = GlobalVar.Container.BeginLifetimeScope())
|
||||
{
|
||||
List<ProcessMethodAttribute> methodList = scope.Resolve<List<ProcessMethodAttribute>>();
|
||||
var method = methodList.FirstOrDefault(u => u.MethodCode == MethodCode);
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
opType = method.DeviceType;
|
||||
BackupConfig = ConfigFactory.GetOperationConfig(opType);
|
||||
}
|
||||
}
|
||||
|
||||
if (OpConfig == null)
|
||||
{
|
||||
OpConfig = ConfigFactory.GetOperationConfig(opType);
|
||||
}
|
||||
else
|
||||
{
|
||||
BackupConfig.DataFrom(OpConfig);
|
||||
}
|
||||
|
||||
propGrid.SelectedObject = OpConfig;
|
||||
}
|
||||
}
|
||||
}
|
120
src/BRS.Common.Model/Forms/FrmOpConfigEdit.resx
Normal file
120
src/BRS.Common.Model/Forms/FrmOpConfigEdit.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
39
src/BRS.Common.Model/GlobalVar.cs
Normal file
39
src/BRS.Common.Model/GlobalVar.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using Autofac;
|
||||
|
||||
namespace BRS.Common.Model
|
||||
{
|
||||
public static class GlobalVar
|
||||
{
|
||||
|
||||
public const string SEPERATOR = "|";
|
||||
|
||||
public static ContainerBuilder Builder { get; set; } = new ContainerBuilder();
|
||||
|
||||
private static object containerLock = new object();
|
||||
|
||||
private static IContainer container = null;
|
||||
public static IContainer Container
|
||||
{
|
||||
get
|
||||
{
|
||||
if (container == null)
|
||||
{
|
||||
lock (containerLock)
|
||||
{
|
||||
if (container == null)
|
||||
{
|
||||
container = Builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
//public static void InitialAutoFac()
|
||||
//{
|
||||
// Container = Builder.Build();
|
||||
//}
|
||||
}
|
||||
}
|
165
src/BRS.Common.Model/Helper/AttributeHelper.cs
Normal file
165
src/BRS.Common.Model/Helper/AttributeHelper.cs
Normal file
@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备特性,指示该信息的设备类型,适用于设备信息和配置信息
|
||||
/// </summary>
|
||||
public class DeviceAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备类型
|
||||
/// </summary>
|
||||
public string TypeCode { get; set; }
|
||||
|
||||
public string TypeDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 特性修饰类别
|
||||
/// </summary>
|
||||
public DeviceAttributeType AttrType { get; set; }
|
||||
|
||||
public DeviceAttribute(string typeCode, string typeDesc, EnumHelper.DeviceAttributeType attrType)
|
||||
{
|
||||
TypeCode = typeCode;
|
||||
TypeDescription = typeDesc;
|
||||
AttrType = attrType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预置状态特性 指定该修饰信息的前置状态允许范围
|
||||
/// </summary>
|
||||
public class PreStateAttribute : Attribute
|
||||
{
|
||||
public int PreState { get; set; }
|
||||
public PreStateAttribute(int _preState)
|
||||
{
|
||||
PreState = _preState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查当前待执行操作的前置状态要求是否合法
|
||||
/// </summary>
|
||||
/// <param name="currentState"></param>
|
||||
/// <returns></returns>
|
||||
public bool CheckPreStateValid(int currentState)
|
||||
{
|
||||
return (currentState & PreState) == currentState;
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorSelectAttribute : Attribute
|
||||
{
|
||||
public string SelectedColor { get; set; }
|
||||
public ColorSelectAttribute(string selectedColor)
|
||||
{
|
||||
SelectedColor = selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
public class FontColorSelectAttribute : Attribute
|
||||
{
|
||||
public string SelectedColor { get; set; }
|
||||
public FontColorSelectAttribute(string selectedColor)
|
||||
{
|
||||
SelectedColor = selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 方法调用方式
|
||||
/// </summary>
|
||||
public enum InvokeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 不公开调用
|
||||
/// </summary>
|
||||
[Description("不公开调用")]
|
||||
NoneInvoke = 0,
|
||||
/// <summary>
|
||||
/// 测试调用
|
||||
/// </summary>
|
||||
[Description("测试调用")]
|
||||
TestInvoke = 1,
|
||||
/// <summary>
|
||||
/// 标定调用
|
||||
/// </summary>
|
||||
[Description("标定调用")]
|
||||
CalibInvoke = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用来修饰对外开放的调用方法的特性
|
||||
/// 调用方法参数顺序:IOperationConfig,InvokeDevice,SourceDevice
|
||||
/// </summary>
|
||||
public class ProcessMethodAttribute : Attribute
|
||||
{
|
||||
public string MethodCode { get; set; }
|
||||
public string MethodDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否提供人工调用测试
|
||||
/// </summary>
|
||||
public InvokeType InvokeType { get; set; }
|
||||
|
||||
public string DeviceType { get; set; }
|
||||
|
||||
public ProcessMethodAttribute(string deviceType, string code, string description, InvokeType invokeType)
|
||||
{
|
||||
DeviceType = deviceType;
|
||||
MethodCode = code;
|
||||
MethodDesc = description;
|
||||
InvokeType = invokeType;
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchDisplayAttribute : Attribute
|
||||
{
|
||||
public string SwitchName { get; set; }
|
||||
|
||||
public bool SwithOnStatus { get; set; } = true;
|
||||
|
||||
public SwitchDisplayAttribute(string name, bool status)
|
||||
{
|
||||
SwitchName = name;
|
||||
SwithOnStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
public class ElementAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Desc { get; set; }
|
||||
|
||||
public string IconPath { get; set; }
|
||||
|
||||
public bool IsShowInToolBar { get; set; }
|
||||
|
||||
public ElementAttribute(string desc, string iconPath, bool isShowInToolBar = true, [CallerMemberName] string name = "")
|
||||
{
|
||||
Name = name;
|
||||
Desc = desc;
|
||||
IconPath = iconPath;
|
||||
IsShowInToolBar = isShowInToolBar;
|
||||
}
|
||||
}
|
||||
|
||||
public class ProcessAttribute : Attribute
|
||||
{
|
||||
public string ProcessCode { get; set; }
|
||||
public DeviceAttributeType AttrType { get; set; }
|
||||
|
||||
public ProcessAttribute(string stationCode, DeviceAttributeType attrType)
|
||||
{
|
||||
ProcessCode = stationCode;
|
||||
AttrType = attrType;
|
||||
}
|
||||
}
|
||||
}
|
43
src/BRS.Common.Model/Helper/CPUHelper.cs
Normal file
43
src/BRS.Common.Model/Helper/CPUHelper.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public static class CPUHelper
|
||||
{
|
||||
//获取系统运行时间毫秒级别
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetTickCount();
|
||||
|
||||
//SetThreadAffinityMask 指定hThread 运行在 核心 dwThreadAffinityMask
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);
|
||||
|
||||
//得到当前线程的handler
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr GetCurrentThread();
|
||||
|
||||
//函数中的参数 dwThreadAffinityMask 为无符号长整型,用位标识那个核心
|
||||
//比如:为简洁使用四位表示
|
||||
//0x0001表示核心1,
|
||||
//0x0010表示核心2,
|
||||
//0x0100表示核心3,
|
||||
//0x1000表示核心4
|
||||
public static ulong SetCpuID(int id)
|
||||
{
|
||||
ulong cpuid = 0;
|
||||
if (id < 0 || id >= System.Environment.ProcessorCount)
|
||||
{
|
||||
id = 0;
|
||||
}
|
||||
cpuid |= 1UL << id;
|
||||
return cpuid;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
130
src/BRS.Common.Model/Helper/CSVHelper.cs
Normal file
130
src/BRS.Common.Model/Helper/CSVHelper.cs
Normal file
@ -0,0 +1,130 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class CSVHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnCSVExceptionRaised;
|
||||
Dictionary<string, CSVSet> csvSetDict = new Dictionary<string, CSVSet>();
|
||||
|
||||
//private string baseDirectory = "";
|
||||
//public string BaseDirectory
|
||||
//{
|
||||
// get => baseDirectory;
|
||||
// set
|
||||
// {
|
||||
// baseDirectory = value;
|
||||
// if (string.IsNullOrWhiteSpace(baseDirectory) || !Path.IsPathRooted(baseDirectory))
|
||||
// {
|
||||
// baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CSV");
|
||||
// }
|
||||
|
||||
// //if (!Directory.Exists(baseDirectory))
|
||||
// //{
|
||||
// // Directory.CreateDirectory(baseDirectory);
|
||||
// //}
|
||||
// }
|
||||
//}
|
||||
public bool EnableCSVRecord { get; set; } = true;
|
||||
|
||||
object lockObj = new object();
|
||||
|
||||
public async void CSVOutputAsync(string fullname, string data, string head = "")
|
||||
{
|
||||
if (!EnableCSVRecord)
|
||||
return;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (!csvSetDict.ContainsKey(fullname))
|
||||
{
|
||||
lock (lockObj)
|
||||
{
|
||||
if (!csvSetDict.ContainsKey(fullname))
|
||||
{
|
||||
csvSetDict[fullname] = new CSVSet()
|
||||
{
|
||||
FullName = fullname,
|
||||
CSVHead = head,
|
||||
};
|
||||
|
||||
csvSetDict[fullname].CSVTask = new Task(async (k) =>
|
||||
{
|
||||
|
||||
CSVSet set = csvSetDict[k.ToString()];
|
||||
try
|
||||
{
|
||||
lock (set.LockObj)
|
||||
{
|
||||
if (!StaticHelper.CheckFilesCanUse(set.FullName))
|
||||
{
|
||||
OnCSVExceptionRaised?.Invoke(DateTime.Now, $"CSV文件{set.FullName}被占用,无法写入");
|
||||
return;
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(set.FullName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(set.FullName));
|
||||
}
|
||||
set.IsFileCreated = File.Exists(set.FullName);
|
||||
}
|
||||
using (StreamWriter writer = new StreamWriter(set.FullName, true, Encoding.UTF8))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
lock (set.LockObj)
|
||||
{
|
||||
if (!set.IsFileCreated)
|
||||
{
|
||||
writer.WriteLine(set.CSVHead);
|
||||
set.IsFileCreated = true;
|
||||
}
|
||||
|
||||
while (set.CSVData.Count > 0)
|
||||
{
|
||||
if (set.CSVData.TryDequeue(out string singleData))
|
||||
{
|
||||
writer.WriteLine(singleData);
|
||||
}
|
||||
}
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnCSVExceptionRaised?.Invoke(DateTime.Now, $"CSV文件{set.FullName}写入异常:{ex.GetExceptionMessage()}");
|
||||
}
|
||||
}, fullname);
|
||||
|
||||
csvSetDict[fullname].CSVTask.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
csvSetDict[fullname].CSVData.Enqueue(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class CSVSet
|
||||
{
|
||||
public string FullName { get; set; } = "";
|
||||
public object LockObj { get; set; } = new object();
|
||||
public Task CSVTask { get; set; } = null;
|
||||
public string CSVHead { get; set; } = "";
|
||||
public ConcurrentQueue<string> CSVData { get; set; } = new ConcurrentQueue<string>();
|
||||
public bool IsFileCreated { get; set; } = false;
|
||||
|
||||
}
|
||||
}
|
120
src/BRS.Common.Model/Helper/ChartHelper.cs
Normal file
120
src/BRS.Common.Model/Helper/ChartHelper.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms.DataVisualization.Charting;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class ChartHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Name:添加序列
|
||||
/// </summary>
|
||||
/// <param name="chart">图表对象</param>
|
||||
/// <param name="seriesName">序列名称</param>
|
||||
/// <param name="chartType">图表类型</param>
|
||||
/// <param name="color">颜色</param>
|
||||
/// <param name="markColor">标记点颜色</param>
|
||||
/// <param name="showValue">是否显示数值</param>
|
||||
public static void AddSeries(Chart chart, string seriesName, SeriesChartType chartType, Color color, Color markColor, bool showValue = false)
|
||||
{
|
||||
chart.Series.Add(seriesName);
|
||||
chart.Series[seriesName].ChartType = chartType;
|
||||
chart.Series[seriesName].Color = color;
|
||||
if (showValue)
|
||||
{
|
||||
chart.Series[seriesName].IsValueShownAsLabel = true;
|
||||
//chart.Series[seriesName].MarkerStyle = MarkerStyle.Circle;
|
||||
//chart.Series[seriesName].MarkerColor = markColor;
|
||||
chart.Series[seriesName].LabelForeColor = markColor;
|
||||
//chart.Series[seriesName].LabelAngle = -90;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name:设置标题
|
||||
/// </summary>
|
||||
/// <param name="chart">图表对象</param>
|
||||
/// <param name="chartName">图表名称</param>
|
||||
public static void SetTitle(Chart chart, string chartName, Font font, Docking docking, Color foreColor)
|
||||
{
|
||||
chart.Titles.Add(chartName);
|
||||
chart.Titles[0].Font = font;
|
||||
chart.Titles[0].Docking = docking;
|
||||
chart.Titles[0].ForeColor = foreColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name:设置样式
|
||||
/// </summary>
|
||||
/// <param name="chart">图表对象</param>
|
||||
/// <param name="backColor">背景颜色</param>
|
||||
/// <param name="foreColor">字体颜色</param>
|
||||
public static void SetStyle(Chart chart, Color backColor, Color foreColor)
|
||||
{
|
||||
chart.BackColor = backColor;
|
||||
chart.ChartAreas[0].BackColor = backColor;
|
||||
chart.ForeColor = Color.Red;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name:设置图例
|
||||
/// </summary>
|
||||
/// <param name="chart">图表对象</param>
|
||||
/// <param name="docking">停靠位置</param>
|
||||
/// <param name="align">对齐方式</param>
|
||||
/// <param name="backColor">背景颜色</param>
|
||||
/// <param name="foreColor">字体颜色</param>
|
||||
public static void SetLegend(Chart chart, Docking docking, StringAlignment align, Color backColor, Color foreColor)
|
||||
{
|
||||
chart.Legends[0].Docking = docking;
|
||||
chart.Legends[0].Alignment = align;
|
||||
chart.Legends[0].BackColor = backColor;
|
||||
chart.Legends[0].ForeColor = foreColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name:设置XY轴
|
||||
/// </summary>
|
||||
/// <param name="chart">图表对象</param>
|
||||
/// <param name="xTitle">X轴标题</param>
|
||||
/// <param name="yTitle">Y轴标题</param>
|
||||
/// <param name="align">坐标轴标题对齐方式</param>
|
||||
/// <param name="foreColor">坐标轴字体颜色</param>
|
||||
/// <param name="lineColor">坐标轴颜色</param>
|
||||
/// <param name="arrowStyle">坐标轴箭头样式</param>
|
||||
/// <param name="xInterval">X轴的间距</param>
|
||||
/// <param name="yInterval">Y轴的间距</param>
|
||||
public static void SetXY(Chart chart, string xTitle, string yTitle, StringAlignment align, Color foreColor, Color lineColor, AxisArrowStyle arrowStyle, double xInterval, double yInterval)
|
||||
{
|
||||
chart.ChartAreas[0].AxisX.Title = xTitle;
|
||||
chart.ChartAreas[0].AxisY.Title = yTitle;
|
||||
chart.ChartAreas[0].AxisX.TitleAlignment = align;
|
||||
chart.ChartAreas[0].AxisY.TitleAlignment = align;
|
||||
chart.ChartAreas[0].AxisX.TitleForeColor = foreColor;
|
||||
chart.ChartAreas[0].AxisY.TitleForeColor = foreColor;
|
||||
chart.ChartAreas[0].AxisX.LabelStyle = new LabelStyle() { ForeColor = foreColor };
|
||||
chart.ChartAreas[0].AxisY.LabelStyle = new LabelStyle() { ForeColor = foreColor };
|
||||
chart.ChartAreas[0].AxisX.LineColor = lineColor;
|
||||
chart.ChartAreas[0].AxisY.LineColor = lineColor;
|
||||
chart.ChartAreas[0].AxisX.ArrowStyle = arrowStyle;
|
||||
chart.ChartAreas[0].AxisY.ArrowStyle = arrowStyle;
|
||||
chart.ChartAreas[0].AxisX.Interval = xInterval;
|
||||
chart.ChartAreas[0].AxisY.Interval = yInterval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name:设置网格
|
||||
/// </summary>
|
||||
/// <param name="chart">图表对象</param>
|
||||
/// <param name="lineColor">网格线颜色</param>
|
||||
/// <param name="xInterval">X轴网格的间距</param>
|
||||
/// <param name="yInterval">Y轴网格的间距</param>
|
||||
public static void SetMajorGrid(Chart chart, Color lineColor, double xInterval, double yInterval)
|
||||
{
|
||||
chart.ChartAreas[0].AxisX.MajorGrid.LineColor = lineColor;
|
||||
chart.ChartAreas[0].AxisY.MajorGrid.LineColor = lineColor;
|
||||
chart.ChartAreas[0].AxisX.MajorGrid.Interval = xInterval;
|
||||
chart.ChartAreas[0].AxisY.MajorGrid.Interval = yInterval;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
878
src/BRS.Common.Model/Helper/EnumHelper.cs
Normal file
878
src/BRS.Common.Model/Helper/EnumHelper.cs
Normal file
@ -0,0 +1,878 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public static class EnumHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据枚举的代码名称获取枚举列表信息
|
||||
/// </summary>
|
||||
/// <param name="enumName"></param>
|
||||
/// <returns></returns>
|
||||
public static List<dynamic> GetEnumListByName(string enumName, string assemblyName = "Common.Model.Helper.EnumHelper+")
|
||||
{
|
||||
List<dynamic> list = new List<dynamic>();
|
||||
|
||||
string fullName = assemblyName + enumName;
|
||||
|
||||
Type t = typeof(EnumHelper).Assembly.GetType(fullName);
|
||||
|
||||
t.GetEnumNames().ToList().ForEach(e =>
|
||||
{
|
||||
int value = Convert.ToInt32(Enum.Parse(t, e));
|
||||
string desc = ((Enum)Enum.Parse(t, e)).GetEnumDescription();
|
||||
var item = new { Value = value, Desc = desc, Code = e };
|
||||
list.Add(item);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举的列表信息,一般供下拉列表使用
|
||||
/// </summary>
|
||||
/// <param name="enumType">枚举类型</param>
|
||||
/// <returns>Desc:中文描述 Value:整形值 Code:枚举值</returns>
|
||||
public static List<dynamic> GetEnumListByType(Type enumType)
|
||||
{
|
||||
List<dynamic> list = new List<dynamic>();
|
||||
|
||||
enumType.GetEnumNames().ToList().ForEach(e =>
|
||||
{
|
||||
int value = Convert.ToInt32(Enum.Parse(enumType, e));
|
||||
string desc = ((Enum)Enum.Parse(enumType, e)).GetEnumDescription();
|
||||
var item = new { Value = value, Desc = desc, Code = e };
|
||||
list.Add(item);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取具体某一枚举的中文描述
|
||||
/// </summary>
|
||||
/// <param name="enumObj"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetEnumDescription(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
if (f == null)
|
||||
{
|
||||
return enumObj.ToString();
|
||||
}
|
||||
DescriptionAttribute attr = f.GetCustomAttribute<DescriptionAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return attr.Description;
|
||||
}
|
||||
else
|
||||
{
|
||||
return enumObj.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static System.Windows.Media.Color GetEnumSelectedMediaColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
var prop = typeof(System.Windows.Media.Colors).GetProperties().FirstOrDefault(p => p.Name == attr.SelectedColor);
|
||||
if (prop != null)
|
||||
{
|
||||
return (System.Windows.Media.Color)prop.GetValue(null);
|
||||
}
|
||||
}
|
||||
return System.Windows.Media.Colors.Transparent;
|
||||
}
|
||||
|
||||
public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Drawing.Color.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Drawing.Color.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetEnumSelectedColorString(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return attr.SelectedColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Transparent";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当枚举牵涉到状态变换,检查现状态是否满足待转换的状态的前置状态要求
|
||||
/// </summary>
|
||||
/// <param name="stateToBe"></param>
|
||||
/// <param name="currentState"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CheckPreStateValid(this Enum stateToBe, int currentState)
|
||||
{
|
||||
Type t = stateToBe.GetType();
|
||||
FieldInfo f = t.GetField(stateToBe.ToString());
|
||||
|
||||
PreStateAttribute attr = f.GetCustomAttribute<PreStateAttribute>();
|
||||
if (attr == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return attr.CheckPreStateValid(currentState);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备状态定义
|
||||
/// 未初始化和异常状态无前置状态要求
|
||||
/// 初始化操作前置状态必须是未初始化、关闭状态和异常状态
|
||||
/// 打开前置必须是初始化和暂停
|
||||
/// 关闭前置必须是打开和暂停和异常
|
||||
/// 暂停前置必须是打开
|
||||
/// </summary>
|
||||
public enum DeviceState
|
||||
{
|
||||
TBD = -1,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[FontColorSelect("Black")]
|
||||
[Description("未初始化")]
|
||||
DSUninit = 1,
|
||||
|
||||
[ColorSelect("Gold")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(1 + 2 + 4 + 8 + 32)]
|
||||
[Description("初始化")]
|
||||
DSInit = 2,
|
||||
|
||||
[ColorSelect("Lime")]
|
||||
[FontColorSelect("Black")]
|
||||
[PreState(2 + 4 + 16)]
|
||||
[Description("运行中")]
|
||||
DSOpen = 4,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(1 + 4 + 8 + 16 + 32)]
|
||||
[Description("关闭")]
|
||||
DSClose = 8,
|
||||
|
||||
[ColorSelect("Gold")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(4 + 16)]
|
||||
[Description("暂停")]
|
||||
DSPause = 16,
|
||||
|
||||
[ColorSelect("Red")]
|
||||
[FontColorSelect("White")]
|
||||
[Description("异常")]
|
||||
DSExcept = 32
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工序状态
|
||||
/// </summary>
|
||||
public enum RunState
|
||||
{
|
||||
[ColorSelect("Gold")]
|
||||
[Description("空闲")]
|
||||
Idle = 1,
|
||||
|
||||
[ColorSelect("Lime")]
|
||||
[Description("运行中")]
|
||||
Running = 2,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[Description("停止")]
|
||||
Stop = 3,
|
||||
|
||||
[ColorSelect("Red")]
|
||||
[Description("宕机")]
|
||||
Down = 99,
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Flags]
|
||||
public enum DeviceAttributeType
|
||||
{
|
||||
[Description("设备驱动")]
|
||||
Device = 1,
|
||||
|
||||
[Description("初始配置")]
|
||||
InitialConfig = 2,
|
||||
|
||||
|
||||
[Description("操作配置")]
|
||||
OperationConfig = 4,
|
||||
|
||||
|
||||
[Description("设备配置")]
|
||||
DeviceConfig = 8,
|
||||
|
||||
|
||||
[Description("输入配置")]
|
||||
InputConfig = 16,
|
||||
|
||||
[Description("初始配置控件")]
|
||||
InitialConfigCtrl = 32,
|
||||
|
||||
|
||||
[Description("操作配置控件")]
|
||||
OperationConfigCtrl = 64,
|
||||
|
||||
|
||||
[Description("设备配置控件")]
|
||||
DeviceConfigCtrl = 128,
|
||||
|
||||
|
||||
[Description("输入配置控件")]
|
||||
InputConfigCtrl = 256,
|
||||
|
||||
|
||||
[Description("运行控件")]
|
||||
RunCtrl = 512,
|
||||
|
||||
[Description("操作配置面板")]
|
||||
OperationConfigPanel = 1024,
|
||||
}
|
||||
|
||||
public enum EnableState
|
||||
{
|
||||
[Description("启用")]
|
||||
Enabled = 0,
|
||||
[Description("禁用")]
|
||||
Disabled = 1,
|
||||
}
|
||||
|
||||
public enum EnableStateFilter
|
||||
{
|
||||
[Description("全部")]
|
||||
All = -1,
|
||||
[Description("启用")]
|
||||
Enabled = 0,
|
||||
[Description("禁用")]
|
||||
Disabled = 1,
|
||||
}
|
||||
|
||||
public enum OutputResult
|
||||
{
|
||||
[Description("OK")]
|
||||
OK = 1,
|
||||
[Description("NG")]
|
||||
NG = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PLC项目的值的类型
|
||||
/// </summary>
|
||||
public enum PLCItemType
|
||||
{
|
||||
[Description("布尔类型")]
|
||||
Bool = 0,
|
||||
[Description("整型")]
|
||||
Integer = 1,
|
||||
[Description("字符串型")]
|
||||
String = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对PLC项目的操作类型
|
||||
/// </summary>
|
||||
public enum PLCOpType
|
||||
{
|
||||
[Description("读取")]
|
||||
Read = 1,
|
||||
[Description("写入")]
|
||||
Write = 2,
|
||||
[Description("监控")]
|
||||
Monitor = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 报警监控 1+8
|
||||
/// </summary>
|
||||
[Description("报警监控")]
|
||||
WarningMonitor = 9,
|
||||
|
||||
/// <summary>
|
||||
/// CT监控 1+16
|
||||
/// </summary>
|
||||
[Description("CT监控")]
|
||||
CTMonitor = 17,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 相机运行模式
|
||||
/// </summary>
|
||||
public enum CameraOpMode
|
||||
{
|
||||
[Description("单次拍照")]
|
||||
SingleSnapShot = 1,
|
||||
[Description("连续模式")]
|
||||
ContinuousMode = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志类型
|
||||
/// </summary>
|
||||
public enum LogType
|
||||
{
|
||||
[Description("警告信息")]
|
||||
Exception_Warning = 1,
|
||||
[Description("错误信息")]
|
||||
Exception_Error = 2,
|
||||
[Description("致命信息")]
|
||||
Exception_Fatal = 3,
|
||||
|
||||
[Description("设备信息")]
|
||||
Info_Device = 11,
|
||||
[Description("工序信息")]
|
||||
Info_Process = 12,
|
||||
[Description("操作信息")]
|
||||
Info_Operation = 13,
|
||||
|
||||
[Description("用户操作信息")]
|
||||
User_Operation = 21,
|
||||
|
||||
[Description("测量结果")]
|
||||
MeasureResult = 31,
|
||||
}
|
||||
|
||||
//public enum CameraDriverType
|
||||
//{
|
||||
// Halcon,
|
||||
// //HalconPlugIn,
|
||||
// Hik,
|
||||
//}
|
||||
|
||||
//public enum ImageType
|
||||
//{
|
||||
// Bmp,
|
||||
// Png,
|
||||
// Jpeg,
|
||||
//}
|
||||
|
||||
//public enum ReplyValue
|
||||
//{
|
||||
// OK = 1,
|
||||
// NG = -1,
|
||||
// IGNORE = -999,
|
||||
//}
|
||||
|
||||
public enum PriorityDirection
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
public enum ElementState
|
||||
{
|
||||
New = 1,
|
||||
MouseHover = 2,
|
||||
MouseInSide = 3,
|
||||
Selected = 4,
|
||||
Moving = 5,
|
||||
Editing = 6,
|
||||
|
||||
Normal = 11,
|
||||
|
||||
Measuring = 21,
|
||||
MeasureDoneOK = 22,
|
||||
MeasureDoneNG = 23,
|
||||
|
||||
CanStretchLeft = 41,
|
||||
CanStretchRight = 42,
|
||||
CanStretchTop = 43,
|
||||
CanStretchBottom = 44,
|
||||
|
||||
CanStretchLeftUpperCorner = 45,
|
||||
CanStretchLeftLowerCorner = 46,
|
||||
CanStretchRightUpperCorner = 47,
|
||||
CanStretchRightLowerCorner = 48,
|
||||
|
||||
StretchingLeft = 31,
|
||||
StretchingRight = 32,
|
||||
StretchingTop = 33,
|
||||
StretchingBottom = 34,
|
||||
|
||||
StretchingLeftUpperCorner = 35,
|
||||
StretchingLeftLowerCorner = 36,
|
||||
StretchingRightUpperCorner = 37,
|
||||
StretchingRightLowerCorner = 38,
|
||||
}
|
||||
|
||||
public enum MouseState
|
||||
{
|
||||
Normal = 1,
|
||||
HoverElement = 2,
|
||||
InSideElement = 3,
|
||||
|
||||
MoveElement = 4,
|
||||
|
||||
StretchingLeft = 11,
|
||||
StretchingRight = 12,
|
||||
StretchingTop = 13,
|
||||
StretchingBottom = 14,
|
||||
|
||||
StretchingLeftUpperCorner = 15,
|
||||
StretchingLeftLowerCorner = 16,
|
||||
StretchingRightUpperCorner = 17,
|
||||
StretchingRightLowerCorner = 18,
|
||||
|
||||
New = 21,
|
||||
Editing = 22,
|
||||
//SelectedElement = 23,
|
||||
|
||||
MovingAll = 31,
|
||||
|
||||
SelectionZone = 41,
|
||||
SelectionZoneDoing = 42,
|
||||
}
|
||||
|
||||
public enum RunMode
|
||||
{
|
||||
[Description("调试模式")]
|
||||
DebugMode = 0,
|
||||
|
||||
[Description("正常运行模式")]
|
||||
NormalMode = 1,
|
||||
|
||||
[Description("模拟模式")]
|
||||
DemoMode = 2,
|
||||
}
|
||||
|
||||
public enum MoveType
|
||||
{
|
||||
[Description("绝对运动")]
|
||||
AbsoluteMove = 1,
|
||||
[Description("机器人坐标系相对运动")]
|
||||
RobotRelativeMove = 2,
|
||||
[Description("相对某个基准点位的相对运动")]
|
||||
BasedPointRelativeMove = 3,
|
||||
[Description("回原点")]
|
||||
Origin = 4,
|
||||
[Description("左侧姿势")]
|
||||
LeftPose = 6,
|
||||
[Description("右侧姿势")]
|
||||
RightPose = 5,
|
||||
[Description("前侧姿势")]
|
||||
FrontPose = 7,
|
||||
[Description("相机坐标系相对运动")]
|
||||
CameraRelativeMove = 12,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 马达/运动板卡运行模式
|
||||
/// </summary>
|
||||
public enum MotionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 普通点位运动
|
||||
/// </summary>
|
||||
[Description("普通点位运动")]
|
||||
P2P = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 找正限位运动
|
||||
/// </summary>
|
||||
[Description("找正限位运动")]
|
||||
FindPositive = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 离开正限位
|
||||
/// </summary>
|
||||
[Description("离开正限位")]
|
||||
LeavePositive = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 找负限位运动
|
||||
/// </summary>
|
||||
[Description("找负限位运动")]
|
||||
FindNegative = 6,
|
||||
|
||||
/// <summary>
|
||||
/// 离开负限位
|
||||
/// </summary>
|
||||
[Description("离开负限位")]
|
||||
LeaveNegative = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 找原点运动
|
||||
/// </summary>
|
||||
[Description("回原点运动")]
|
||||
GoHome = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Jog模式
|
||||
/// </summary>
|
||||
[Description("Jog模式")]
|
||||
Jog = 9,
|
||||
|
||||
///// <summary>
|
||||
///// 读数头找原点方式
|
||||
///// </summary>
|
||||
//[Description("找原点inde")]
|
||||
//FindOriIndex = 10,
|
||||
|
||||
///// <summary>
|
||||
///// 插补模式
|
||||
///// </summary>
|
||||
//[Description("插补模式")]
|
||||
//Coordinate = 11
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IO预定义类型 主要针对输出
|
||||
/// </summary>
|
||||
public enum IOPrestatement
|
||||
{
|
||||
[Description("自定义")]
|
||||
Customized = 0,
|
||||
|
||||
[Description("指示灯-黄")]
|
||||
Light_Yellow = 1,
|
||||
[Description("指示灯-绿")]
|
||||
Light_Green = 2,
|
||||
[Description("指示灯-红")]
|
||||
Light_Red = 3,
|
||||
[Description("蜂鸣器")]
|
||||
Beep = 4,
|
||||
[Description("照明灯")]
|
||||
Light = 5,
|
||||
|
||||
[Description("急停")]
|
||||
EmergencyStop = 99,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTS运动板卡控制返回控制码
|
||||
/// </summary>
|
||||
public enum GTSRetCode
|
||||
{
|
||||
[Description("指令执行成功")]
|
||||
GRCRunOK = 0, // 指令执行成功
|
||||
[Description("指令执行错误")]
|
||||
GRCRunErr = 1, // 指令执行错误
|
||||
[Description("icense不支持")]
|
||||
GRCNotSupport = 2, // icense不支持
|
||||
[Description("指令参数错误")]
|
||||
GRCInvalidParam = 7, // 指令参数错误
|
||||
[Description("主机和运动控制器通讯失败")]
|
||||
GRCCommErr = -1, // 主机和运动控制器通讯失败
|
||||
[Description("打开控制器失败")]
|
||||
GRCOpenErr = -6, // 打开控制器失败
|
||||
[Description("运动控制器没有响应")]
|
||||
GRCNotAck = -7 // 运动控制器没有响应
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运动板卡 IO 类型(IN OUT)
|
||||
/// </summary>
|
||||
public enum IOType
|
||||
{
|
||||
[Description("INPUT")]
|
||||
INPUT = 0,
|
||||
[Description("OUTPUT")]
|
||||
OUTPUT = 1
|
||||
}
|
||||
|
||||
public enum IOValue
|
||||
{
|
||||
[Description("关闭")]
|
||||
FALSE = 0,
|
||||
[Description("开启")]
|
||||
TRUE = 1,
|
||||
[Description("反转")]
|
||||
REVERSE = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PubSubCenter事件中心的消息类型
|
||||
/// </summary>
|
||||
public enum PubSubCenterMessageType
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行界面更新产品下拉
|
||||
/// </summary>
|
||||
[Description("更新产品下拉")]
|
||||
UpdateProductionCodes,
|
||||
|
||||
/// <summary>
|
||||
/// 流程是否关闭
|
||||
/// </summary>
|
||||
[Description("流程是否打开")]
|
||||
IsProcessOpened,
|
||||
|
||||
/// <summary>
|
||||
/// 清除数据
|
||||
/// </summary>
|
||||
[Description("清除数据")]
|
||||
ClearData,
|
||||
/// <summary>
|
||||
/// 更新批次信息
|
||||
/// </summary>
|
||||
[Description("更新批次信息")]
|
||||
UpdateBatchNO,
|
||||
/// <summary>
|
||||
/// 请求批次信息
|
||||
/// </summary>
|
||||
[Description("更新批次信息")]
|
||||
RequestBatchNO,
|
||||
}
|
||||
|
||||
public enum MachineState
|
||||
{
|
||||
Unknown = 0,
|
||||
Ready = 1,
|
||||
Running = 2,
|
||||
Alarm = 3,
|
||||
Pause = 4,
|
||||
Resetting = 5,
|
||||
Closing = 6,
|
||||
ClearProduct = 7,
|
||||
}
|
||||
|
||||
public enum WhoolSize
|
||||
{
|
||||
Size17=0,
|
||||
Size16,
|
||||
Size18,
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum MachineStateStep
|
||||
{
|
||||
Unknown = 0,
|
||||
Ready ,//上电就绪
|
||||
|
||||
inflation,//充气气
|
||||
Running ,//硫化
|
||||
Bleeding,//放气
|
||||
Alarm ,
|
||||
Pause ,
|
||||
Resetting ,
|
||||
Closing ,
|
||||
ClearProduct ,
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum RobotsStatus
|
||||
{
|
||||
Unknown = 0,
|
||||
Inplace ,
|
||||
Claming,
|
||||
Relasing,
|
||||
Moving ,
|
||||
Wating ,
|
||||
Pweroff,
|
||||
Reset ,
|
||||
|
||||
}
|
||||
public enum ProcessStatus
|
||||
{
|
||||
Unknown = 0,
|
||||
/// <summary>
|
||||
/// 初始化点
|
||||
/// </summary>
|
||||
Init,
|
||||
|
||||
MesureingInit,
|
||||
MesureingInitPLC,
|
||||
Mesureing ,
|
||||
MesureingPLC,
|
||||
Claim ,
|
||||
ClaimPLC,
|
||||
Runing ,
|
||||
RunFinish,
|
||||
Loosen,
|
||||
LoosenPLC,
|
||||
TakeOffMove,
|
||||
TakeOffMovePLC,
|
||||
TakeOffMovePLC_2,
|
||||
TakeOff,/// <summary>
|
||||
/// 取出轮胎
|
||||
/// </summary>
|
||||
///
|
||||
TakeOffCaim,
|
||||
TakeOffPLC,
|
||||
TakeOffPoint,
|
||||
TakeOffPointCaim,
|
||||
TakeOffPointCaimFlag,
|
||||
TakeOffWhool,
|
||||
Resetting ,
|
||||
Closing ,
|
||||
ClearProduct ,
|
||||
}
|
||||
|
||||
|
||||
public enum ResultState
|
||||
{
|
||||
[Description("NA")]
|
||||
NA = -5,
|
||||
//[Description("尺寸NG")]
|
||||
//SizeNG = -4,
|
||||
[Description("检测NG")]
|
||||
NG = -1,
|
||||
//[Description("A类NG")]
|
||||
//A_NG = -3,
|
||||
//[Description("C类NG")]
|
||||
//C_NG = -2,
|
||||
//[Description("B类NG")]
|
||||
//B_NG = -1,
|
||||
|
||||
[Description("OK")]
|
||||
OK = 1,
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum HikCameraType
|
||||
{
|
||||
[Description("HikCamera-Gige")]
|
||||
Gige = 0,
|
||||
[Description("HikCamera-USB")]
|
||||
USB = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 光源操作
|
||||
/// </summary>
|
||||
public enum LightOperation
|
||||
{
|
||||
[Description("打开")]
|
||||
Open = 1,
|
||||
[Description("关闭")]
|
||||
Close = 2,
|
||||
[Description("写入")]
|
||||
Write = 3,
|
||||
[Description("读取")]
|
||||
Read = 4,
|
||||
[Description("频闪")]
|
||||
Flash = 5,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 监听反馈数据值
|
||||
/// </summary>
|
||||
public enum ReturnValue
|
||||
{
|
||||
OKVALUE = 1,
|
||||
NGVALUE = -1,
|
||||
EXCEPTIONVALUE = -2,
|
||||
UNAUTHORIZATION = -10,
|
||||
IGNORE = -999,
|
||||
}
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
[Description("辅助")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Blue")]
|
||||
Assist = 1,
|
||||
[Description("详细")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Green")]
|
||||
Detail = 2,
|
||||
[Description("信息")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Dark")]
|
||||
Information = 3,
|
||||
[Description("动作")]
|
||||
[ColorSelect("DarkGreen")]
|
||||
[FontColorSelect("Yellow")]
|
||||
Action = 4,
|
||||
|
||||
|
||||
[Description("错误")]
|
||||
[ColorSelect("Orange")]
|
||||
[FontColorSelect("White")]
|
||||
Error = 5,
|
||||
|
||||
|
||||
[Description("警报")]
|
||||
[ColorSelect("Brown")]
|
||||
[FontColorSelect("White")]
|
||||
Warning = 6,
|
||||
|
||||
|
||||
[Description("异常")]
|
||||
[ColorSelect("Red")]
|
||||
[FontColorSelect("White")]
|
||||
Exception = 7,
|
||||
}
|
||||
|
||||
|
||||
public enum DetectionDeviceTypeDef
|
||||
{
|
||||
[Description("CPU")]
|
||||
CPU = 0,
|
||||
|
||||
[Description("GPU")]
|
||||
GPU,
|
||||
|
||||
[Description("VPU")]
|
||||
VPU,
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public enum DetectImageFormat
|
||||
//{
|
||||
// [Description("所有格式")]
|
||||
// ALL = 0,
|
||||
// [Description("JPEG")]
|
||||
// JPEG = 1,
|
||||
// [Description("PNG")]
|
||||
// PNG = 2,
|
||||
// [Description("TIFF")]
|
||||
// TIFF = 3,
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
106
src/BRS.Common.Model/Helper/FactoryHelper.cs
Normal file
106
src/BRS.Common.Model/Helper/FactoryHelper.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using Bro.Common.Interface;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Bro.Common.Helper
|
||||
{
|
||||
public class StationFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取StationProcess
|
||||
/// </summary>
|
||||
/// <param name="stationCode">站点编号 S1~S7</param>
|
||||
/// <param name="userName">登录用户名称</param>
|
||||
/// <param name="msg">异常信息</param>
|
||||
/// <returns></returns>
|
||||
public static IProcess CreateStationProcess(string stationCode, string userName, out string msg)
|
||||
{
|
||||
IProcess proc = null;
|
||||
msg = "";
|
||||
|
||||
try
|
||||
{
|
||||
var dllFiles = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).GetFiles("Bro.*.dll").Select(u => u.FullName).ToList();
|
||||
|
||||
foreach (string f in dllFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly assm = Assembly.LoadFrom(f);
|
||||
if (assm != null)
|
||||
{
|
||||
foreach (Type t in assm.GetTypes())
|
||||
{
|
||||
if (typeof(IProcess).IsAssignableFrom(t))
|
||||
{
|
||||
var attr = t.GetCustomAttribute<ProcessAttribute>();
|
||||
if (attr != null && attr.ProcessCode == stationCode)
|
||||
{
|
||||
proc = Activator.CreateInstance(t, userName) as IProcess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.GetExceptionMessage();
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取StationConfig
|
||||
/// </summary>
|
||||
/// <param name="stationCode">站点编号 S1~S7</param>
|
||||
/// <param name="msg">异常信息</param>
|
||||
/// <returns></returns>
|
||||
public static IProcessConfig CreateStationConfig(string stationCode, out string msg)
|
||||
{
|
||||
IProcessConfig config = null;
|
||||
msg = "";
|
||||
|
||||
try
|
||||
{
|
||||
var dllFiles = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).GetFiles("Bro.*.dll").Select(u => u.FullName).ToList();
|
||||
|
||||
foreach (string f in dllFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly assm = Assembly.LoadFrom(f);
|
||||
if (assm != null)
|
||||
{
|
||||
foreach (Type t in assm.GetTypes())
|
||||
{
|
||||
if (typeof(IProcessConfig).IsAssignableFrom(t))
|
||||
{
|
||||
var attr = t.GetCustomAttribute<ProcessAttribute>();
|
||||
if (attr != null && attr.ProcessCode == stationCode)
|
||||
{
|
||||
config = Activator.CreateInstance(t) as IProcessConfig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.GetExceptionMessage();
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
106
src/BRS.Common.Model/Helper/ImageSaveHelper.cs
Normal file
106
src/BRS.Common.Model/Helper/ImageSaveHelper.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class ImageSaveHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnImageSaveExceptionRaised;
|
||||
|
||||
//private string baseDirectory = "";
|
||||
//public string BaseDirectory
|
||||
//{
|
||||
// get => baseDirectory;
|
||||
// set
|
||||
// {
|
||||
// baseDirectory = value;
|
||||
// if (string.IsNullOrWhiteSpace(baseDirectory) || !Path.IsPathRooted(baseDirectory))
|
||||
// {
|
||||
// baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
public bool EnableImageSave { get; set; } = true;
|
||||
|
||||
public ImageSaveHelper() { }
|
||||
public ImageSaveHelper(bool enableImageSave = true)
|
||||
{
|
||||
EnableImageSave = enableImageSave;
|
||||
}
|
||||
|
||||
|
||||
object lockObj = new object();
|
||||
////耗时操作从 _taskFactory分配线程
|
||||
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
readonly ConcurrentQueue<ImageSaveSet> _imageQueue = new ConcurrentQueue<ImageSaveSet>();
|
||||
Task _saveTask = null;
|
||||
readonly object _saveLock = new object();
|
||||
|
||||
public async void ImageSaveAsync(ImageSaveSet set)
|
||||
{
|
||||
if (!EnableImageSave)
|
||||
return;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_imageQueue.Enqueue(set);
|
||||
|
||||
lock (_saveLock)
|
||||
{
|
||||
if (_saveTask == null)
|
||||
{
|
||||
_saveTask = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (_imageQueue.Count > 0)
|
||||
{
|
||||
if (_imageQueue.TryDequeue(out ImageSaveSet saveSet))
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(saveSet.FullName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(saveSet.FullName));
|
||||
}
|
||||
if (saveSet.SaveImage != null)
|
||||
{
|
||||
saveSet.SaveImage.Save(saveSet.FullName, saveSet.ImageFormat);
|
||||
saveSet.SaveImage.Dispose();
|
||||
}
|
||||
saveSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnImageSaveExceptionRaised?.Invoke(DateTime.Now, $"图片保存异常:{ex.GetExceptionMessage()}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageSaveSet
|
||||
{
|
||||
public string FullName { get; set; }//带后缀 全路径
|
||||
|
||||
public Bitmap SaveImage { get; set; }
|
||||
|
||||
public ImageFormat ImageFormat { get; set; } = ImageFormat.Png;
|
||||
}
|
||||
}
|
24
src/BRS.Common.Model/Helper/JsonHelper.cs
Normal file
24
src/BRS.Common.Model/Helper/JsonHelper.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class IPAddressConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(IPAddress));
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
return IPAddress.Parse((string)reader.Value);
|
||||
}
|
||||
}
|
||||
}
|
118
src/BRS.Common.Model/Helper/ListHelper.cs
Normal file
118
src/BRS.Common.Model/Helper/ListHelper.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class NoticedList<T> : List<T> where T : class
|
||||
{
|
||||
public Action<NotifyCollectionChangedAction> OnItemChanged;
|
||||
|
||||
public Action<NotifyCollectionChangedAction, List<T>> OnItemChangedWithItemInfo;
|
||||
|
||||
//public Action<NotifyCollectionChangedAction, NoticedList<T>> OnItemChangedWithSelf;
|
||||
|
||||
public new T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index >= 0 && index < Count)
|
||||
{
|
||||
return base[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
set
|
||||
{
|
||||
if (base[index] != value)
|
||||
{
|
||||
base[index] = value;
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Replace);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Replace, new List<T>() { value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public new void Add(T item)
|
||||
{
|
||||
base.Add(item);
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, new List<T>() { item });
|
||||
}
|
||||
|
||||
public new void AddRange(IEnumerable<T> collection)
|
||||
{
|
||||
base.AddRange(collection);
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, collection.ToList());
|
||||
}
|
||||
|
||||
public new void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Reset);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Reset, this);
|
||||
}
|
||||
|
||||
public new void Insert(int index, T item)
|
||||
{
|
||||
base.Insert(index, item);
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, new List<T>() { item });
|
||||
}
|
||||
|
||||
public new void InsertRange(int index, IEnumerable<T> collection)
|
||||
{
|
||||
base.InsertRange(index, collection);
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, collection.ToList());
|
||||
}
|
||||
|
||||
public new bool Remove(T item)
|
||||
{
|
||||
bool flag = base.Remove(item);
|
||||
|
||||
if (flag)
|
||||
{
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, new List<T>() { item });
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public new int RemoveAll(Predicate<T> match)
|
||||
{
|
||||
List<T> temp = this.Where(u => match.Invoke(u)).ToList();
|
||||
int i = base.RemoveAll(match);
|
||||
if (i > 0)
|
||||
{
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, temp);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public new void RemoveAt(int index)
|
||||
{
|
||||
var item = this[index];
|
||||
base.RemoveAt(index);
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, new List<T>() { item });
|
||||
}
|
||||
|
||||
public new void RemoveRange(int index, int count)
|
||||
{
|
||||
List<T> temp = this.Skip(index).Take(count).ToList();
|
||||
base.RemoveRange(index, count);
|
||||
OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
|
||||
OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, temp);
|
||||
}
|
||||
}
|
||||
}
|
131
src/BRS.Common.Model/Helper/LoggerHelper.cs
Normal file
131
src/BRS.Common.Model/Helper/LoggerHelper.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class LoggerHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnLogExceptionRaised;
|
||||
|
||||
public string LogPath { get; set; }
|
||||
public string LogPrefix { get; set; }
|
||||
|
||||
LogLevel LogLevel = LogLevel.Information;
|
||||
|
||||
public LoggerHelper() { }
|
||||
public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information)
|
||||
{
|
||||
LogPath = logPath;
|
||||
LogPrefix = logPrefix;
|
||||
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
|
||||
public void SetLogLevel(LogLevel logLevel)
|
||||
{
|
||||
if (LogLevel != logLevel)
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
////耗时操作从 _taskFactory分配线程
|
||||
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>();
|
||||
Task _logTask = null;
|
||||
readonly object _logLock = new object();
|
||||
|
||||
public async void LogAsync(LogMsg msg)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(LogPath) || string.IsNullOrWhiteSpace(LogPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_logQueue.Enqueue(msg);
|
||||
|
||||
lock (_logLock)
|
||||
{
|
||||
if (_logTask == null)
|
||||
{
|
||||
_logTask = Task.Run(async () =>
|
||||
{
|
||||
string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt");
|
||||
|
||||
try
|
||||
{
|
||||
if (!StaticHelper.CheckFilesCanUse(filePath))
|
||||
{
|
||||
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用,无法写入");
|
||||
return;
|
||||
}
|
||||
using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!Directory.Exists(LogPath))
|
||||
{
|
||||
Directory.CreateDirectory(LogPath);
|
||||
}
|
||||
|
||||
while (_logQueue.Count > 0)
|
||||
{
|
||||
if (_logQueue.TryDequeue(out LogMsg log))
|
||||
{
|
||||
if (log.LogLevel >= LogLevel)
|
||||
{
|
||||
writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}\t{log.Msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.Flush();
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常:{ex.GetExceptionMessage()}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public class LogMsg
|
||||
{
|
||||
public DateTime LogTime { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
//public string Prefix { get; set; }
|
||||
public string Msg { get; set; }
|
||||
|
||||
public string MsgSource { get; set; }
|
||||
|
||||
public int ThreadId { get; set; }
|
||||
|
||||
public LogMsg() { }
|
||||
public LogMsg(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogTime = dt;
|
||||
LogLevel = logLevel;
|
||||
Msg = msg;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}";
|
||||
}
|
||||
}
|
||||
}
|
890
src/BRS.Common.Model/Helper/ModbusRTUHelper.cs
Normal file
890
src/BRS.Common.Model/Helper/ModbusRTUHelper.cs
Normal file
@ -0,0 +1,890 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace Bro.Common.Helper
|
||||
{
|
||||
/*
|
||||
* MODBUS协议
|
||||
*
|
||||
*
|
||||
* 介绍:
|
||||
* 此modbus上位机 协议类 具有较强的通用性
|
||||
* 本协议类最主要的思想是 把所有向下位机发送的指令 先存放在缓冲区中(命名为管道)
|
||||
* 再将管道中的指令逐个发送出去。
|
||||
* 管道遵守FIFO的模式。管道中所存放指令的个数 在全局变量中定义。
|
||||
* 管道内主要分为两部分:1,定时循环发送指令。2,一次性发送指令。
|
||||
* 定时循环发送指令:周期性间隔时间发送指令,一般针对“输入寄存器”或“输入线圈”等实时更新的变量。
|
||||
* 这两部分的长度由用户所添加指令个数决定(所以自由性强)。
|
||||
* 指令的最大发送次数,及管道中最大存放指令的个数在常量定义中 可进行设定。
|
||||
*
|
||||
* 使用说明:
|
||||
* 1,首先对所定义的寄存器或线圈进行分组定义,并定义首地址。
|
||||
* 2,在MBDataTable数组中添加寄存器或线圈所对应的地址。 注意 寄存器:ob = new UInt16()。线圈:ob = new byte()。
|
||||
* 3,对所定义的地址 用属性进行定义 以方便在类外进行访问及了解所对应地址的含义。
|
||||
* 4,GetAddressValueLength函数中 对使用说明的"第一步"分组 的元素个数进行指定。
|
||||
* 5,在主程序中调用MBConfig进行协议初始化(初始化内容参考函数)。
|
||||
* 6,在串口中断函数中调用MBDataReceive()。
|
||||
* 7,定时器调用MBRefresh()。(10ms以下)
|
||||
* 指令发送间隔时间等于实时器乘以10。 例:定时器5ms调用一次 指令发送间隔为50ms。
|
||||
* 8,在主程序初始化中添加固定实时发送的指令操作 用MBAddRepeatCmd函数。
|
||||
* 9,在主程序运行过程中 根据需要添加 单个的指令操作(非固定重复发送的指令)用MBAddCmd函数。
|
||||
*
|
||||
*
|
||||
* 作者:王宏强
|
||||
* 时间:2012.7.2
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
public class ModbusRTUHelper
|
||||
{
|
||||
#region 所用结构体
|
||||
/// <summary>
|
||||
/// 地址对应表元素单元
|
||||
/// </summary>
|
||||
public struct OPTable
|
||||
{
|
||||
public volatile int addr;
|
||||
public volatile byte type;
|
||||
public volatile object ob;
|
||||
};
|
||||
/// <summary>
|
||||
/// 当前的指令
|
||||
/// </summary>
|
||||
public struct MBCmd
|
||||
{
|
||||
public volatile int addr; //指令首地址
|
||||
public volatile int stat; //功能码
|
||||
public volatile int len; //所操作的寄存器或线圈的个数
|
||||
public volatile int res; //返回码的状态, 0:无返回,1:正确返回
|
||||
};
|
||||
/// <summary>
|
||||
/// 当前操作的指令管道
|
||||
/// </summary>
|
||||
public struct MBSci
|
||||
{
|
||||
public volatile MBCmd[] cmd; //指令结构体
|
||||
public volatile int index; //当前索引
|
||||
public volatile int count; //当前功能码执行的次数
|
||||
public volatile int maxRepeatCount; //最大发送次数
|
||||
public volatile int rtCount; //实时读取的指令各数(无限间隔时间读取)
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region 常量定义
|
||||
public const byte MB_READ_COILS = 0x01; //读线圈寄存器
|
||||
public const byte MB_READ_DISCRETE = 0x02; //读离散输入寄存器
|
||||
public const byte MB_READ_HOLD_REG = 0x03; //读保持寄存器
|
||||
public const byte MB_READ_INPUT_REG = 0x04; //读输入寄存器
|
||||
public const byte MB_WRITE_SINGLE_COIL = 0x05; //写单个线圈
|
||||
public const byte MB_WRITE_SINGLE_REG = 0x06; //写单寄存器
|
||||
public const byte MB_WRITE_MULTIPLE_COILS = 0x0f; //写多线圈
|
||||
public const byte MB_WRITE_MULTIPLE_REGS = 0x10; //写多寄存器
|
||||
|
||||
private const int MB_MAX_LENGTH = 120; //最大数据长度
|
||||
private const int MB_SCI_MAX_COUNT = 15; //指令管道最大存放的指令各数
|
||||
private const int MB_MAX_REPEAT_COUNT = 3; //指令最多发送次数
|
||||
#endregion
|
||||
|
||||
#region 全局变量
|
||||
private static volatile bool sciLock = false; //调度器锁 true:加锁 false:解锁
|
||||
private static volatile byte[] buff = new byte[MB_MAX_LENGTH]; //接收缓冲器
|
||||
private static volatile int buffLen = 0;
|
||||
private static volatile byte[] rBuff = null; //正确接收缓冲器
|
||||
private static volatile byte[] wBuff = null; //正确发送缓冲器
|
||||
public static MBSci gMBSci = new MBSci() { cmd = new MBCmd[MB_SCI_MAX_COUNT], index = 0, maxRepeatCount = MB_MAX_REPEAT_COUNT, rtCount = 0, count = 0 };
|
||||
private static SerialPort comm = null;
|
||||
private static int mbRefreshTime = 0;
|
||||
#endregion
|
||||
|
||||
#region MODBUS 地址对应表
|
||||
//modbus寄存器和线圈分组 首地址定义
|
||||
public const int D_DIO = 0x0000;
|
||||
public const int D_BASE = 0x0014;
|
||||
public const int D_RANGE = 0x0018;
|
||||
public const int D_PWM = 0x001A;
|
||||
public const int D_PID = 0x001E;
|
||||
|
||||
/// <summary>
|
||||
/// 变量所对应的地址 在此位置
|
||||
/// </summary>
|
||||
public static volatile OPTable[] MBDataTable =
|
||||
{
|
||||
new OPTable(){addr = D_DIO, type = MB_READ_INPUT_REG, ob = new UInt16()}, //0
|
||||
new OPTable(){addr = D_DIO + 1, type = MB_READ_INPUT_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_DIO + 2, type = MB_READ_INPUT_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_DIO + 3, type = MB_READ_INPUT_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_DIO + 4, type = MB_READ_INPUT_REG, ob = new Int16()},
|
||||
new OPTable(){addr = D_DIO + 5, type = MB_READ_INPUT_REG, ob = new Int16()},
|
||||
|
||||
new OPTable(){addr = D_BASE, type = MB_READ_HOLD_REG, ob = new Int16()}, //6
|
||||
new OPTable(){addr = D_BASE + 1, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
new OPTable(){addr = D_BASE + 2, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
new OPTable(){addr = D_BASE + 3, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
|
||||
new OPTable(){addr = D_RANGE, type = MB_READ_HOLD_REG, ob = new Int16()}, //10
|
||||
new OPTable(){addr = D_RANGE + 1, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
|
||||
new OPTable(){addr = D_PWM, type = MB_READ_HOLD_REG, ob = new Int16()}, //12
|
||||
new OPTable(){addr = D_PWM + 1, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
new OPTable(){addr = D_PWM + 2, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
new OPTable(){addr = D_PWM + 3, type = MB_READ_HOLD_REG, ob = new Int16()},
|
||||
|
||||
new OPTable(){addr = D_PID, type = MB_READ_HOLD_REG, ob = new UInt16()}, //16
|
||||
new OPTable(){addr = D_PID + 1, type = MB_READ_HOLD_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_PID + 2, type = MB_READ_HOLD_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_PID + 3, type = MB_READ_HOLD_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_PID + 4, type = MB_READ_HOLD_REG, ob = new UInt16()},
|
||||
new OPTable(){addr = D_PID + 5, type = MB_READ_HOLD_REG, ob = new UInt16()},
|
||||
|
||||
};
|
||||
public static UInt16 gDioX { get { return Convert.ToUInt16(MBDataTable[0].ob); } set { MBDataTable[0].ob = value; } }
|
||||
public static UInt16 gDioY { get { return Convert.ToUInt16(MBDataTable[1].ob); } set { MBDataTable[1].ob = value; } }
|
||||
public static UInt16 gDioZ { get { return Convert.ToUInt16(MBDataTable[2].ob); } set { MBDataTable[2].ob = value; } }
|
||||
public static UInt16 gDioD { get { return Convert.ToUInt16(MBDataTable[3].ob); } set { MBDataTable[3].ob = value; } }
|
||||
public static Int16 gDioXx { get { return (Int16)Convert.ToInt32(MBDataTable[4].ob); } set { MBDataTable[4].ob = value; } }
|
||||
public static Int16 gDioXy { get { return (Int16)Convert.ToInt32(MBDataTable[5].ob); } set { MBDataTable[5].ob = value; } }
|
||||
|
||||
public static Int16 gBaseF1 { get { return (Int16)Convert.ToInt32(MBDataTable[6].ob); } set { MBDataTable[6].ob = value; } }
|
||||
public static Int16 gBaseF2 { get { return (Int16)Convert.ToInt32(MBDataTable[7].ob); } set { MBDataTable[7].ob = value; } }
|
||||
public static Int16 gBaseF3 { get { return (Int16)Convert.ToInt32(MBDataTable[8].ob); } set { MBDataTable[8].ob = value; } }
|
||||
public static Int16 gBaseF4 { get { return (Int16)Convert.ToInt32(MBDataTable[9].ob); } set { MBDataTable[9].ob = value; } }
|
||||
|
||||
public static Int16 gRangeMax { get { return (Int16)Convert.ToInt32(MBDataTable[10].ob); } set { MBDataTable[10].ob = value; } }
|
||||
public static Int16 gRangeMin { get { return (Int16)Convert.ToInt32(MBDataTable[11].ob); } set { MBDataTable[11].ob = value; } }
|
||||
|
||||
public static Int16 gPwmF1 { get { return (Int16)Convert.ToInt32(MBDataTable[12].ob); } set { MBDataTable[12].ob = value; } }
|
||||
public static Int16 gPwmF2 { get { return (Int16)Convert.ToInt32(MBDataTable[13].ob); } set { MBDataTable[13].ob = value; } }
|
||||
public static Int16 gPwmF3 { get { return (Int16)Convert.ToInt32(MBDataTable[14].ob); } set { MBDataTable[14].ob = value; } }
|
||||
public static Int16 gPwmF4 { get { return (Int16)Convert.ToInt32(MBDataTable[15].ob); } set { MBDataTable[15].ob = value; } }
|
||||
|
||||
public static float gP
|
||||
{
|
||||
get
|
||||
{
|
||||
int tmp = (Convert.ToInt32(MBDataTable[16].ob) & 0xFFFF) | ((Convert.ToInt32(MBDataTable[17].ob) & 0xFFFF) << 16);
|
||||
byte[] arr = BitConverter.GetBytes(tmp);
|
||||
return BitConverter.ToSingle(arr, 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
byte[] val = BitConverter.GetBytes(value);
|
||||
MBDataTable[16].ob = BitConverter.ToUInt16(val, 0);
|
||||
MBDataTable[17].ob = BitConverter.ToUInt16(val, 2);
|
||||
}
|
||||
}
|
||||
public static float gI
|
||||
{
|
||||
get
|
||||
{
|
||||
int tmp = (Convert.ToInt32(MBDataTable[18].ob) & 0xFFFF) | ((Convert.ToInt32(MBDataTable[19].ob) & 0xFFFF) << 16);
|
||||
byte[] arr = BitConverter.GetBytes(tmp);
|
||||
return BitConverter.ToSingle(arr, 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
byte[] val = BitConverter.GetBytes(value);
|
||||
MBDataTable[18].ob = BitConverter.ToUInt16(val, 0);
|
||||
MBDataTable[19].ob = BitConverter.ToUInt16(val, 2);
|
||||
}
|
||||
}
|
||||
public static float gD
|
||||
{
|
||||
get
|
||||
{
|
||||
int tmp = (Convert.ToInt32(MBDataTable[20].ob) & 0xFFFF) | ((Convert.ToInt32(MBDataTable[21].ob) & 0xFFFF) << 16);
|
||||
byte[] arr = BitConverter.GetBytes(tmp);
|
||||
return BitConverter.ToSingle(arr, 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
byte[] val = BitConverter.GetBytes(value);
|
||||
MBDataTable[20].ob = BitConverter.ToUInt16(val, 0);
|
||||
MBDataTable[21].ob = BitConverter.ToUInt16(val, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public static UInt16 gNode = 100;
|
||||
public static UInt16 gBaud = 38400;
|
||||
/// <summary>
|
||||
/// 获取寄存器或线圈 分组后的成员各数
|
||||
/// </summary>
|
||||
/// <param name="addr">首地址</param>
|
||||
/// <returns>成员各数</returns>
|
||||
private static int GetAddressValueLength(int addr)
|
||||
{
|
||||
int res = 0;
|
||||
switch (addr)
|
||||
{
|
||||
case D_DIO: res = 6; break;
|
||||
case D_BASE: res = 4; break;
|
||||
case D_RANGE: res = 2; break;
|
||||
case D_PWM: res = 4; break;
|
||||
case D_PID: res = 6; break;
|
||||
default: break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取地址所对应的数据
|
||||
/// </summary>
|
||||
/// <param name="addr">地址</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>获取到的数据</returns>
|
||||
private static object GetAddressValue(int addr, byte type)
|
||||
{
|
||||
switch (type) //功能码类型判断
|
||||
{
|
||||
case MB_READ_COILS:
|
||||
case MB_READ_DISCRETE:
|
||||
case MB_READ_HOLD_REG:
|
||||
case MB_READ_INPUT_REG: break;
|
||||
case MB_WRITE_SINGLE_COIL:
|
||||
case MB_WRITE_MULTIPLE_COILS: type = MB_READ_DISCRETE; break;
|
||||
case MB_WRITE_SINGLE_REG:
|
||||
case MB_WRITE_MULTIPLE_REGS: type = MB_READ_HOLD_REG; break;
|
||||
default: return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MBDataTable.Length; i++)
|
||||
{
|
||||
if (MBDataTable[i].addr == addr)
|
||||
{
|
||||
if (MBDataTable[i].type == type)
|
||||
{
|
||||
return MBDataTable[i].ob;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置地址所对应的数据
|
||||
/// </summary>
|
||||
/// <param name="addr">地址</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="data">数据</param>
|
||||
/// <returns>是否成功</returns>
|
||||
private static object SetAddressValue(int addr, byte type, object data)
|
||||
{
|
||||
for (int i = 0; i < MBDataTable.Length; i++)
|
||||
{
|
||||
if (MBDataTable[i].addr == addr)
|
||||
{
|
||||
if (MBDataTable[i].type == type)
|
||||
{
|
||||
MBDataTable[i].ob = data;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取一连串数据
|
||||
/// </summary>
|
||||
/// <param name="addr">首地址</param>
|
||||
/// <param name="type">功能码</param>
|
||||
/// <param name="len">长度</param>
|
||||
/// <returns>转换后的字节数组</returns>
|
||||
private static byte[] GetAddressValues(int addr, byte type, int len)
|
||||
{
|
||||
byte[] arr = null;
|
||||
object obj;
|
||||
byte temp;
|
||||
int temp2;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MB_WRITE_MULTIPLE_COILS:
|
||||
arr = new byte[(len % 8 == 0) ? (len / 8) : (len / 8 + 1)];
|
||||
for (int i = 0; i < arr.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < 8; j++)
|
||||
{ //获取地址所对应的数据 并判断所读数据 是否被指定,有没被指定的数据 直接返回null
|
||||
obj = GetAddressValue(addr + i * 8 + j, MB_READ_COILS);
|
||||
if (obj == null)
|
||||
return null;
|
||||
else
|
||||
temp = Convert.ToByte(obj);
|
||||
arr[i] |= (byte)((temp == 0 ? 0 : 1) << j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MB_WRITE_MULTIPLE_REGS:
|
||||
arr = new byte[len * 2];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
obj = GetAddressValue(addr + i, MB_READ_HOLD_REG);
|
||||
if (obj == null)
|
||||
return null;
|
||||
else
|
||||
temp2 = Convert.ToInt32(obj);
|
||||
arr[i * 2] = (byte)(temp2 >> 8);
|
||||
arr[i * 2 + 1] = (byte)(temp2 & 0xFF);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 校验
|
||||
private static readonly byte[] aucCRCHi = {
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40
|
||||
};
|
||||
private static readonly byte[] aucCRCLo = {
|
||||
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
|
||||
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
|
||||
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
|
||||
0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
|
||||
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
|
||||
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
|
||||
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
|
||||
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
|
||||
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
|
||||
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
|
||||
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
|
||||
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
|
||||
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
|
||||
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
|
||||
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
|
||||
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
|
||||
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
|
||||
0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
|
||||
0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
|
||||
0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
|
||||
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
|
||||
0x41, 0x81, 0x80, 0x40
|
||||
};
|
||||
/// <summary>
|
||||
/// CRC效验
|
||||
/// </summary>
|
||||
/// <param name="pucFrame">效验数据</param>
|
||||
/// <param name="usLen">数据长度</param>
|
||||
/// <returns>效验结果</returns>
|
||||
public static int Crc16(byte[] pucFrame, int usLen)
|
||||
{
|
||||
int i = 0;
|
||||
byte ucCRCHi = 0xFF;
|
||||
byte ucCRCLo = 0xFF;
|
||||
UInt16 iIndex = 0x0000;
|
||||
|
||||
while (usLen-- > 0)
|
||||
{
|
||||
iIndex = (UInt16)(ucCRCLo ^ pucFrame[i++]);
|
||||
ucCRCLo = (byte)(ucCRCHi ^ aucCRCHi[iIndex]);
|
||||
ucCRCHi = aucCRCLo[iIndex];
|
||||
}
|
||||
return (ucCRCHi << 8 | ucCRCLo);
|
||||
}
|
||||
|
||||
public static byte[] Crc16InBytes(byte[] pucFrame, int usLen)
|
||||
{
|
||||
int i = 0;
|
||||
byte ucCRCHi = 0xFF;
|
||||
byte ucCRCLo = 0xFF;
|
||||
UInt16 iIndex = 0x0000;
|
||||
|
||||
while (usLen-- > 0)
|
||||
{
|
||||
iIndex = (UInt16)(ucCRCLo ^ pucFrame[i++]);
|
||||
ucCRCLo = (byte)(ucCRCHi ^ aucCRCHi[iIndex]);
|
||||
ucCRCHi = aucCRCLo[iIndex];
|
||||
}
|
||||
return new byte[2] { ucCRCLo, ucCRCHi };
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 发送指命操作
|
||||
/// <summary>
|
||||
/// 首部分数据 node:节点
|
||||
/// </summary>
|
||||
/// <param name="addr">寄存器地址</param>
|
||||
/// <param name="len">数据长度,或单个数据</param>
|
||||
/// <param name="stat"></param>
|
||||
/// <returns></returns>
|
||||
private static byte[] SendTrainHead(int node, int addr, int len, byte stat)
|
||||
{
|
||||
byte[] head = new byte[6];
|
||||
|
||||
head[0] = Convert.ToByte(node);
|
||||
head[1] = stat;
|
||||
head[2] = (byte)(addr >> 8);
|
||||
head[3] = (byte)(addr & 0xFF);
|
||||
head[4] = (byte)(len >> 8);
|
||||
head[5] = (byte)(len & 0xFF);
|
||||
|
||||
return head;
|
||||
}
|
||||
/// <summary>
|
||||
/// 计算数据长度 并在0x0f,0x10功能下 加载字节数
|
||||
/// </summary>
|
||||
/// <param name="arr"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <param name="stat"></param>
|
||||
/// <returns></returns>
|
||||
private static byte[] SendTrainBytes(byte[] arr, ref int len, byte stat)
|
||||
{
|
||||
byte[] res;
|
||||
switch (stat)
|
||||
{
|
||||
default: len = 0; break;
|
||||
|
||||
case MB_READ_COILS:
|
||||
case MB_READ_DISCRETE:
|
||||
case MB_READ_HOLD_REG:
|
||||
case MB_READ_INPUT_REG:
|
||||
case MB_WRITE_SINGLE_COIL:
|
||||
case MB_WRITE_SINGLE_REG:
|
||||
len = 0;
|
||||
break;
|
||||
|
||||
case MB_WRITE_MULTIPLE_COILS:
|
||||
len = (len % 8 == 0) ? (len / 8) : (len / 8 + 1);
|
||||
res = new byte[arr.Length + 1];
|
||||
arr.CopyTo(res, 0);
|
||||
res[arr.Length] = (byte)(len);
|
||||
arr = res;
|
||||
break;
|
||||
|
||||
case MB_WRITE_MULTIPLE_REGS:
|
||||
len *= 2;
|
||||
res = new byte[arr.Length + 1];
|
||||
arr.CopyTo(res, 0);
|
||||
res[arr.Length] = (byte)len; //把字节写入数据最后位置
|
||||
arr = res;
|
||||
break;
|
||||
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
/// <summary>
|
||||
/// 主控方式 发送指令模板
|
||||
/// </summary>
|
||||
/// <param name="node">节点</param>
|
||||
/// <param name="data">数据</param>
|
||||
/// <param name="addr">地址</param>
|
||||
/// <param name="con">变量各数</param>
|
||||
/// <param name="stat">功能码</param>
|
||||
/// <returns></returns>
|
||||
private static byte[] SendTrainCyclostyle(int node, byte[] data, int addr, int con, byte stat)
|
||||
{
|
||||
int crcVal = 0;
|
||||
byte[] headData = SendTrainHead(node, addr, con, stat); //写首部分数据
|
||||
byte[] headDataLen = SendTrainBytes(headData, ref con, stat); //计算数据的长度,有字节则写入。
|
||||
byte[] res = new byte[headDataLen.Length + con + 2];
|
||||
|
||||
headDataLen.CopyTo(res, 0);
|
||||
|
||||
if ((stat == MB_WRITE_MULTIPLE_REGS) || (stat == MB_WRITE_MULTIPLE_COILS))
|
||||
Array.Copy(data, 0, res, headDataLen.Length, con); //把数据复制到数据中
|
||||
|
||||
crcVal = Crc16(res, res.Length - 2);
|
||||
res[res.Length - 2] = (byte)(crcVal & 0xFF);
|
||||
res[res.Length - 1] = (byte)(crcVal >> 8);
|
||||
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 封装发送数据帧
|
||||
/// </summary>
|
||||
/// <param name="node">从机地址</param>
|
||||
/// <param name="cmd">指令信息</param>
|
||||
/// <returns></returns>
|
||||
private static byte[] SendPduPack(int node, MBCmd cmd)
|
||||
{
|
||||
byte[] res = null;
|
||||
switch (cmd.stat)
|
||||
{
|
||||
case MB_READ_COILS:
|
||||
case MB_READ_DISCRETE:
|
||||
case MB_READ_HOLD_REG:
|
||||
case MB_READ_INPUT_REG:
|
||||
case MB_WRITE_SINGLE_COIL:
|
||||
case MB_WRITE_SINGLE_REG:
|
||||
res = SendTrainCyclostyle(node, null, cmd.addr, cmd.len, (byte)cmd.stat); break;
|
||||
|
||||
case MB_WRITE_MULTIPLE_COILS:
|
||||
case MB_WRITE_MULTIPLE_REGS:
|
||||
byte[] data = GetAddressValues(cmd.addr, (byte)cmd.stat, cmd.len);
|
||||
res = SendTrainCyclostyle(node, data, cmd.addr, cmd.len, (byte)cmd.stat); break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 回传数据操作
|
||||
/// <summary>
|
||||
/// 存储回传的线圈
|
||||
/// </summary>
|
||||
/// <param name="data">回传的数组</param>
|
||||
/// <param name="addr">首地址</param>
|
||||
/// <returns>存储是否正确</returns>
|
||||
private static bool ReadDiscrete(byte[] data, int addr)
|
||||
{
|
||||
bool res = true;
|
||||
int len = data[2];
|
||||
|
||||
if (len != (data.Length - 5)) //数据长度不正确 直接退出
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if (SetAddressValue(addr + i * 8 + j, data[1], data[i + 3] & (0x01 << j)) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 读回传的寄存器
|
||||
/// </summary>
|
||||
/// <param name="data">回传的数组</param>
|
||||
/// <param name="addr">首地址</param>
|
||||
/// <returns>存储是否正确</returns>
|
||||
private static bool ReadReg(byte[] data, int addr)
|
||||
{
|
||||
bool res = true;
|
||||
int len = data[2];
|
||||
|
||||
if (len != (data.Length - 5)) //数据长度不正确 直接退出
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < len; i += 2)
|
||||
{
|
||||
if (SetAddressValue(addr + i / 2, data[1], (data[i + 3] << 8) | data[i + 4]) == null)
|
||||
{
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 回传的数据处理
|
||||
/// </summary>
|
||||
/// <param name="buff">回传的整帧数据</param>
|
||||
/// <param name="addr">当前所操作的首地址</param>
|
||||
/// <returns></returns>
|
||||
private static bool ReceiveDataProcess(byte[] buff, int addr)
|
||||
{
|
||||
if (buff == null)
|
||||
return false;
|
||||
if (buff.Length < 5) //回传的数据 地址+功能码+长度+2效验 = 5字节
|
||||
return false;
|
||||
|
||||
bool res = true;
|
||||
switch (buff[1])
|
||||
{
|
||||
case MB_READ_COILS: ReadDiscrete(buff, addr); break;
|
||||
case MB_READ_DISCRETE: ReadDiscrete(buff, addr); break;
|
||||
case MB_READ_HOLD_REG: ReadReg(buff, addr); break;
|
||||
case MB_READ_INPUT_REG: ReadReg(buff, addr); break;
|
||||
case MB_WRITE_SINGLE_COIL:
|
||||
case MB_WRITE_SINGLE_REG:
|
||||
case MB_WRITE_MULTIPLE_COILS:
|
||||
case MB_WRITE_MULTIPLE_REGS: break;
|
||||
default: res = false; break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 收发调度
|
||||
/// <summary>
|
||||
/// 添加重复操作指令
|
||||
/// </summary>
|
||||
/// <param name="sci">待发送的指命管道</param>
|
||||
/// <param name="addr">所添加指令的首地址</param>
|
||||
/// <param name="len">所添加指令的寄存器或线圈个数</param>
|
||||
/// <param name="stat">所添加指令的功能码</param>
|
||||
private static void SciAddRepeatCmd(ref MBSci sci, int addr, int len, int stat)
|
||||
{
|
||||
if (sci.rtCount >= MB_SCI_MAX_COUNT - 1) //超出指令管道最大长度 直接退出
|
||||
return;
|
||||
if (len == 0) //地址的数据长度为空 直接退出
|
||||
return;
|
||||
|
||||
sci.cmd[sci.rtCount].addr = addr;
|
||||
sci.cmd[sci.rtCount].len = len;
|
||||
sci.cmd[sci.rtCount].stat = stat;
|
||||
sci.cmd[sci.rtCount].res = 0;
|
||||
sci.rtCount++;
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加一次性操作指令
|
||||
/// </summary>
|
||||
/// <param name="sci">待发送的指命管道</param>
|
||||
/// <param name="addr">所添加指令的首地址</param>
|
||||
/// <param name="len">所添加指令的寄存器或线圈个数</param>
|
||||
/// <param name="stat">所添加指令的功能码</param>
|
||||
private static void SciAddCmd(ref MBSci sci, int addr, int len, int stat)
|
||||
{
|
||||
if (len == 0) //地址的数据长度为空 直接退出
|
||||
return;
|
||||
|
||||
for (int i = sci.rtCount; i < MB_SCI_MAX_COUNT; i++)
|
||||
{
|
||||
if (sci.cmd[i].addr == -1) //把指令载入到空的管道指令上
|
||||
{
|
||||
sci.cmd[i].addr = addr;
|
||||
sci.cmd[i].len = len;
|
||||
sci.cmd[i].stat = stat;
|
||||
sci.cmd[i].res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 清空重复读取指令集
|
||||
/// </summary>
|
||||
/// <param name="sci">待发送的指命管道</param>
|
||||
private static void SciClearRepeatCmd(ref MBSci sci)
|
||||
{
|
||||
sci.rtCount = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// 清空一次性读取指令集
|
||||
/// </summary>
|
||||
/// <param name="sci">待发送的指命管道</param>
|
||||
private static void SciClearCmd(ref MBSci sci)
|
||||
{
|
||||
for (int i = sci.rtCount; i < MB_SCI_MAX_COUNT; i++)
|
||||
{
|
||||
sci.cmd[i].addr = -1;
|
||||
sci.cmd[i].len = 0;
|
||||
sci.cmd[i].res = 0;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 跳到下一个操作指令
|
||||
/// </summary>
|
||||
/// <param name="sci">待发送的指命管道</param>
|
||||
private static void SciJumbNext(ref MBSci sci)
|
||||
{
|
||||
if (sci.index >= sci.rtCount) //非实时读取地址会被清除
|
||||
{
|
||||
sci.cmd[sci.index].addr = -1;
|
||||
sci.cmd[sci.index].len = 0;
|
||||
sci.cmd[sci.index].stat = 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
sci.index++;
|
||||
if (sci.index >= MB_SCI_MAX_COUNT) //超出指令最大范围
|
||||
{
|
||||
sci.index = 0;
|
||||
if (sci.rtCount == 0) //如果固定实时读取 为空 直接跳出
|
||||
break;
|
||||
}
|
||||
|
||||
} while (sci.cmd[sci.index].addr == -1);
|
||||
sci.cmd[sci.index].res = 0; //本次返回状态清零
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送指令调度锁定
|
||||
/// </summary>
|
||||
public static void SciSchedulingLock()
|
||||
{
|
||||
sciLock = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送指令调度解锁
|
||||
/// </summary>
|
||||
public static void SciSchedulingUnlock()
|
||||
{
|
||||
sciLock = false;
|
||||
}
|
||||
/// <summary>
|
||||
/// 待发送的指令管道调度
|
||||
/// </summary>
|
||||
/// <param name="sci">待发送的指命管道</param>
|
||||
/// <param name="rBuf">收到正确的回传数据</param>
|
||||
/// <param name="wBuf">准备发送的指令数据</param>
|
||||
private static void SciScheduling(ref MBSci sci, ref byte[] rBuf, ref byte[] wBuf)
|
||||
{
|
||||
if (sciLock) //如果被加锁 直接退出
|
||||
return;
|
||||
|
||||
if ((sci.cmd[sci.index].res != 0) || (sci.count >= sci.maxRepeatCount))
|
||||
{
|
||||
sci.count = 0; //发送次数清零
|
||||
if (sci.cmd[sci.index].res != 0) //如果收到了正常返回
|
||||
{
|
||||
ReceiveDataProcess(rBuf, sci.cmd[sci.index].addr); //保存数据
|
||||
rBuf = null; //清空当前接收缓冲区的内容, 以防下次重复读取
|
||||
}
|
||||
else
|
||||
{
|
||||
//参数操作失败
|
||||
}
|
||||
|
||||
SciJumbNext(ref sci);
|
||||
}
|
||||
wBuf = SendPduPack((int)gNode, sci.cmd[sci.index]); //发送指令操作
|
||||
sci.count++; //发送次数加1
|
||||
}
|
||||
/// <summary>
|
||||
/// 快速刷新 处理接收到的数据 建议:10ms以下
|
||||
/// </summary>
|
||||
/// <returns>所正确回传数据的功能码, null:回传不正确</returns>
|
||||
private static int MBQuickRefresh()
|
||||
{
|
||||
int res = -1;
|
||||
if (rBuff != null)
|
||||
{
|
||||
SciSchedulingLock();
|
||||
if (ReceiveDataProcess(rBuff, gMBSci.cmd[gMBSci.index].addr) == true)
|
||||
{
|
||||
gMBSci.cmd[gMBSci.index].res = 1; //标记 所接收到的数据正确
|
||||
res = gMBSci.cmd[gMBSci.index].stat;
|
||||
}
|
||||
rBuff = null;
|
||||
SciSchedulingUnlock();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 调度间隔时间刷新 建议:50ms以上
|
||||
/// </summary>
|
||||
/// <returns>封装好的协议帧</returns>
|
||||
private static void MBSchedRefresh()
|
||||
{
|
||||
SciScheduling(ref gMBSci, ref rBuff, ref wBuff);
|
||||
if (wBuff != null)
|
||||
comm.Write(wBuff, 0, wBuff.Length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 接口函数
|
||||
/// <summary>
|
||||
/// 清空存放一次性的指令空间
|
||||
/// </summary>
|
||||
public static void MBClearCmd()
|
||||
{
|
||||
SciClearCmd(ref gMBSci);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加固定刷新(重复) 操作指令
|
||||
/// </summary>
|
||||
/// <param name="addr">地址</param>
|
||||
/// <param name="stat">功能码</param>
|
||||
public static void MBAddRepeatCmd(int addr, byte stat)
|
||||
{
|
||||
for (int i = 0; i < GetAddressValueLength(addr); i++)
|
||||
if (GetAddressValue(addr, stat) == null) //如果所添加的指令没有在MODBUS对应表中定义 直接退出
|
||||
return;
|
||||
SciAddRepeatCmd(ref gMBSci, addr, GetAddressValueLength(addr), stat);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加一次性 操作指令
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="stat"></param>
|
||||
public static void MBAddCmd(int addr, byte stat)
|
||||
{
|
||||
for (int i = 0; i < GetAddressValueLength(addr); i++)
|
||||
if (GetAddressValue(addr, stat) == null) //如果所添加的指令没有在MODBUS对应表中定义 直接退出
|
||||
return;
|
||||
SciAddCmd(ref gMBSci, addr, GetAddressValueLength(addr), stat);
|
||||
}
|
||||
/// <summary>
|
||||
/// 串口参数配置
|
||||
/// </summary>
|
||||
/// <param name="commx">所用到的串口</param>
|
||||
/// <param name="node"></param>
|
||||
/// <param name="baud"></param>
|
||||
public static void MBConfig(SerialPort commx, UInt16 node, UInt16 baud)
|
||||
{
|
||||
gBaud = baud;
|
||||
gNode = node;
|
||||
comm = commx;
|
||||
SciClearRepeatCmd(ref gMBSci);
|
||||
SciClearCmd(ref gMBSci);
|
||||
}
|
||||
/// <summary>
|
||||
/// 读取串口中接收到的数据
|
||||
/// </summary>
|
||||
/// <param name="comm">所用到的串口</param>
|
||||
public static void MBDataReceive()
|
||||
{
|
||||
if (comm == null) //如果串口没有被初始化直接退出
|
||||
return;
|
||||
SciSchedulingLock();
|
||||
System.Threading.Thread.Sleep(20); //等待缓冲器满
|
||||
|
||||
buffLen = comm.BytesToRead; //获取缓冲区字节长度
|
||||
if (buffLen > MB_MAX_LENGTH) //如果长度超出范围 直接退出
|
||||
{
|
||||
SciSchedulingUnlock();
|
||||
return;
|
||||
}
|
||||
comm.Read(buff, 0, buffLen); //读取数据
|
||||
if (gMBSci.cmd[gMBSci.index].stat == buff[1])
|
||||
{
|
||||
if (Crc16(buff, buffLen) == 0)
|
||||
{
|
||||
rBuff = new byte[buffLen];
|
||||
Array.Copy(buff, rBuff, buffLen);
|
||||
}
|
||||
}
|
||||
SciSchedulingUnlock();
|
||||
}
|
||||
/// <summary>
|
||||
/// MODBUS的实时刷新任务,在定时器在实时调用此函数
|
||||
/// 指令发送间隔时间等于实时器乘以10。 例:定时器5ms调用一次 指令发送间隔为50ms。
|
||||
/// </summary>
|
||||
/// <returns>返回当前功能读取指令回传 的功能码</returns>
|
||||
public static int MBRefresh()
|
||||
{
|
||||
if (sciLock) //如果被加锁 直接退出
|
||||
return 0;
|
||||
|
||||
mbRefreshTime++;
|
||||
if (mbRefreshTime > 10)
|
||||
{
|
||||
mbRefreshTime = 0;
|
||||
MBSchedRefresh();
|
||||
}
|
||||
return MBQuickRefresh();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
1436
src/BRS.Common.Model/Helper/PropertyConvertHelper.cs
Normal file
1436
src/BRS.Common.Model/Helper/PropertyConvertHelper.cs
Normal file
File diff suppressed because it is too large
Load Diff
229
src/BRS.Common.Model/Helper/SettingHelper.cs
Normal file
229
src/BRS.Common.Model/Helper/SettingHelper.cs
Normal file
@ -0,0 +1,229 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public static class SettingHelper
|
||||
{
|
||||
const string SETTINGFILE = "Setting.json";
|
||||
|
||||
public static SettingInfo SettingInfo;
|
||||
|
||||
public static string SettingPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, SETTINGFILE);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查配置文件是否存在且有效
|
||||
/// </summary>
|
||||
/// <returns>如果文件存在且配置内容有效,返回true,否则返回false</returns>
|
||||
public static bool IsSettingFileValid()
|
||||
{
|
||||
if (!File.Exists(SettingPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return null != SettingInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static SettingHelper()
|
||||
{
|
||||
if (!File.Exists(SettingPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(SettingPath, System.Text.Encoding.UTF8))
|
||||
{
|
||||
string dataStr = reader.ReadToEnd();
|
||||
SettingInfo = JsonConvert.DeserializeObject<SettingInfo>(dataStr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitWithContent(string content)
|
||||
{
|
||||
SettingInfo = JsonConvert.DeserializeObject<SettingInfo>(content);
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(SettingPath, false, System.Text.Encoding.UTF8))
|
||||
{
|
||||
writer.Write(content);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string GetSelectedLayout()
|
||||
{
|
||||
return SettingInfo.CurrLayout;
|
||||
}
|
||||
|
||||
public static List<string> GetProductionCodes()
|
||||
{
|
||||
if (SettingInfo.ProductionCodes.Count == 0)
|
||||
{
|
||||
SettingInfo.ProductionCodes.Add("Default");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(SettingInfo.DefaultProduction))
|
||||
{
|
||||
if (SettingInfo.ProductionCodes.Contains(SettingInfo.DefaultProduction))
|
||||
{
|
||||
SettingInfo.ProductionCodes.Remove(SettingInfo.DefaultProduction);
|
||||
SettingInfo.ProductionCodes.Insert(0, SettingInfo.DefaultProduction);
|
||||
}
|
||||
}
|
||||
|
||||
return SettingInfo.ProductionCodes;
|
||||
}
|
||||
|
||||
public static List<string> GetProcessCodes()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(SettingInfo.DefaultProcess))
|
||||
{
|
||||
if (SettingInfo.ProcessCodes.Contains(SettingInfo.DefaultProcess))
|
||||
{
|
||||
SettingInfo.ProcessCodes.Remove(SettingInfo.DefaultProcess);
|
||||
SettingInfo.ProcessCodes.Insert(0, SettingInfo.DefaultProcess);
|
||||
}
|
||||
}
|
||||
|
||||
return SettingInfo.ProcessCodes;
|
||||
}
|
||||
|
||||
public static void AddNewProductionCode(string code)
|
||||
{
|
||||
if (!SettingInfo.ProductionCodes.Contains(code))
|
||||
{
|
||||
SettingInfo.ProductionCodes.Add(code);
|
||||
}
|
||||
|
||||
SaveSettingInfo();
|
||||
}
|
||||
|
||||
public static string GetConfigFilePath()
|
||||
{
|
||||
return SettingInfo.ConfigPath;
|
||||
}
|
||||
|
||||
public static string GetProgramDescription()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SettingInfo.Description))
|
||||
{
|
||||
SettingInfo.Description = "硫化上下料系统";
|
||||
}
|
||||
|
||||
return SettingInfo.Description;
|
||||
}
|
||||
|
||||
public static string GetProgramIcon()
|
||||
{
|
||||
string iconPath = SettingInfo.IconPath;
|
||||
if (string.IsNullOrWhiteSpace(iconPath) || !File.Exists(iconPath))
|
||||
{
|
||||
iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logo.ico");
|
||||
}
|
||||
|
||||
if (!File.Exists(iconPath))
|
||||
{
|
||||
iconPath = "";
|
||||
}
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
#region 保存
|
||||
public static void SetCurrLayout(string name)
|
||||
{
|
||||
if (SettingInfo.CurrLayout != name)
|
||||
{
|
||||
SettingInfo.CurrLayout = name;
|
||||
SaveSettingInfo();
|
||||
}
|
||||
}
|
||||
public static void SetDefaultProcess(string processCode)
|
||||
{
|
||||
if (SettingInfo.DefaultProcess != processCode)
|
||||
{
|
||||
SettingInfo.DefaultProcess = processCode;
|
||||
SaveSettingInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetDefaultProduction(string productionCode)
|
||||
{
|
||||
if (SettingInfo.DefaultProduction != productionCode)
|
||||
{
|
||||
SettingInfo.DefaultProduction = productionCode;
|
||||
SaveSettingInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetDefault(string processCode, string productionCode)
|
||||
{
|
||||
bool isChanged = false;
|
||||
if (SettingInfo.DefaultProcess != processCode)
|
||||
{
|
||||
isChanged = true;
|
||||
SettingInfo.DefaultProcess = processCode;
|
||||
}
|
||||
|
||||
if (SettingInfo.DefaultProduction != productionCode)
|
||||
{
|
||||
isChanged = true;
|
||||
SettingInfo.DefaultProduction = productionCode;
|
||||
}
|
||||
|
||||
if (isChanged)
|
||||
{
|
||||
SaveSettingInfo();
|
||||
}
|
||||
}
|
||||
|
||||
static object saveLock = new object();
|
||||
private static void SaveSettingInfo()
|
||||
{
|
||||
string newDataStr = JsonConvert.SerializeObject(SettingInfo);
|
||||
lock (saveLock)
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(SettingPath, false, System.Text.Encoding.UTF8))
|
||||
{
|
||||
writer.Write(newDataStr);
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class SettingInfo
|
||||
{
|
||||
public List<string> ProcessCodes { get; set; } = new List<string>();
|
||||
public List<string> ProductionCodes { get; set; } = new List<string>();
|
||||
|
||||
public string DefaultProcess { get; set; }
|
||||
|
||||
public string DefaultProduction { get; set; }
|
||||
|
||||
public string ConfigPath { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string IconPath { get; set; }
|
||||
public string CurrLayout { get; set; } = "";
|
||||
|
||||
public bool IsMinimumWhenClose { get; set; } = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
674
src/BRS.Common.Model/Helper/StaticHelper.cs
Normal file
674
src/BRS.Common.Model/Helper/StaticHelper.cs
Normal file
@ -0,0 +1,674 @@
|
||||
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Newtonsoft.Json;
|
||||
using OpenCvSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Threading.Tasks;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public static class StaticHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值转换为byte数组 高位在前,低位在后
|
||||
/// </summary>
|
||||
/// <param name="number"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] IntToBytes(this int number, int size = 2)
|
||||
{
|
||||
byte[] result = new byte[size];
|
||||
|
||||
int temp = size;
|
||||
while (temp > 0)
|
||||
{
|
||||
result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff);
|
||||
|
||||
temp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字节数组转换为整数
|
||||
/// </summary>
|
||||
/// <param name="data">字节数组</param>
|
||||
/// <param name="HtL">true:数组序号低的在高位 false:数组序号低的在低位</param>
|
||||
/// <returns></returns>
|
||||
public static int BytesToInt(this byte[] data, bool HtL = true)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
int index = i;
|
||||
|
||||
if (HtL)
|
||||
{
|
||||
index = data.Length - 1 - i;
|
||||
}
|
||||
|
||||
res += data[index] << (8 * i);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// byte数组转int数组
|
||||
/// </summary>
|
||||
/// <param name="src">源byte数组</param>
|
||||
/// <param name="offset">起始位置</param>
|
||||
/// <returns></returns>
|
||||
public static int[] BytesToInts(this byte[] src, int offset = 0)
|
||||
{
|
||||
int[] values = new int[src.Length / 4];
|
||||
for (int i = 0; i < src.Length / 4; i++)
|
||||
{
|
||||
int value = (int)((src[offset] & 0xFF)
|
||||
| ((src[offset + 1] & 0xFF) << 8)
|
||||
| ((src[offset + 2] & 0xFF) << 16)
|
||||
| ((src[offset + 3] & 0xFF) << 24));
|
||||
values[i] = value;
|
||||
offset += 4;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// int数组转byte数组
|
||||
/// </summary>
|
||||
/// <param name="src">源int数组</param>
|
||||
/// <param name="offset">起始位置,一般为0</param>
|
||||
/// <returns>values</returns>
|
||||
public static byte[] IntsToBytes(this int[] src, int offset = 0)
|
||||
{
|
||||
byte[] values = new byte[src.Length * 4];
|
||||
for (int i = 0; i < src.Length; i++)
|
||||
{
|
||||
|
||||
values[offset + 3] = (byte)((src[i] >> 24) & 0xFF);
|
||||
values[offset + 2] = (byte)((src[i] >> 16) & 0xFF);
|
||||
values[offset + 1] = (byte)((src[i] >> 8) & 0xFF);
|
||||
values[offset] = (byte)(src[i] & 0xFF);
|
||||
offset += 4;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// short数组转int数组
|
||||
/// </summary>
|
||||
/// <param name="src">源int数组</param>
|
||||
/// <param name="offset">起始位置,一般为0</param>
|
||||
/// <returns>values</returns>
|
||||
public static int[] ShortsToInts(this short[] src)
|
||||
{
|
||||
int[] values = new int[src.Length];
|
||||
for (int i = 0; i < src.Length; i++)
|
||||
{
|
||||
values[i] = (int)src[i];
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个类指定的属性值
|
||||
/// </summary>
|
||||
/// <param name="info">object对象</param>
|
||||
/// <param name="field">属性名称</param>
|
||||
/// <returns></returns>
|
||||
public static object GetPropertyValue(object info, string field)
|
||||
{
|
||||
if (info == null) return null;
|
||||
Type t = info.GetType();
|
||||
IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
|
||||
return property.First().GetValue(info, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将32位整形拆分为无符号16位整形
|
||||
/// </summary>
|
||||
/// <param name="num">需要拆分的32位整形</param>
|
||||
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
if (bitNum == 2)
|
||||
{
|
||||
ushort high = (ushort)(num >> 16);
|
||||
ushort low = (ushort)num;
|
||||
|
||||
if (HtL)
|
||||
{
|
||||
return new List<ushort>() { high, low };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<ushort>() { low, high };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num < 0)
|
||||
{
|
||||
num = ushort.MaxValue + 1 + num;
|
||||
}
|
||||
|
||||
return new List<ushort>() { (ushort)num };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将32位整形数组拆分为无符号16位整形数组
|
||||
/// </summary>
|
||||
/// <param name="list">需要拆分的32位整形</param>
|
||||
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将ushort的集合转换为16位带符号整形
|
||||
/// </summary>
|
||||
/// <param name="numList"></param>
|
||||
/// <param name="bitNum">合并的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
if (bitNum == 1)
|
||||
{
|
||||
return numList.ConvertAll(n =>
|
||||
{
|
||||
int num = n;
|
||||
if (num > short.MaxValue)
|
||||
{
|
||||
num = num - ushort.MaxValue - 1;
|
||||
}
|
||||
|
||||
return num;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
List<int> list = new List<int>();
|
||||
for (int i = 0; i < numList.Count; i += 2)
|
||||
{
|
||||
int high = HtL ? numList[i] : numList[i + 1];
|
||||
int low = HtL ? numList[i + 1] : numList[i];
|
||||
list.Add((high << 16) | low);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public static T DeepSerializeClone<T>(this T t)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
|
||||
}
|
||||
|
||||
public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class
|
||||
{
|
||||
if (sourceT == null)
|
||||
{
|
||||
destT = null;
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray();
|
||||
PropertyInfo[] propSource = sourceT.GetType().GetProperties();
|
||||
|
||||
Array.ForEach(propDest, prop =>
|
||||
{
|
||||
if (exceptionProps == null || !exceptionProps.Contains(prop.Name))
|
||||
{
|
||||
if (prop.CanWrite)
|
||||
{
|
||||
PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name);
|
||||
if (propS != null && propS.CanRead)
|
||||
{
|
||||
prop.SetValue(destT, propS.GetValue(sourceT));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Bitmap BitmapSerializeCopy(this Bitmap map)
|
||||
{
|
||||
Bitmap image = null;
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
bf.Serialize(ms, map);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
image = (Bitmap)bf.Deserialize(ms);
|
||||
|
||||
//ms.Close();
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public static Bitmap DeepClone(this Bitmap bitmap)
|
||||
{
|
||||
Bitmap dstBitmap = null;
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
bf.Serialize(mStream, bitmap);
|
||||
mStream.Seek(0, SeekOrigin.Begin);
|
||||
dstBitmap = (Bitmap)bf.Deserialize(mStream);
|
||||
mStream.Close();
|
||||
}
|
||||
return dstBitmap;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
|
||||
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||
[HandleProcessCorruptedStateExceptions]
|
||||
public static Bitmap CopyBitmap(this Bitmap source)
|
||||
{
|
||||
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
try
|
||||
{
|
||||
int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
if (PixelSize == 1)
|
||||
{
|
||||
ColorPalette cp = clone.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
}
|
||||
clone.Palette = cp;
|
||||
}
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
if (source.Width % 4 == 0)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Parallel.For(0, source.Height, h =>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
clone.UnlockBits(cloneData);
|
||||
source.UnlockBits(sourceData);
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
return clone;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static Bitmap BitmapDeepClone(Bitmap source)
|
||||
{
|
||||
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
|
||||
try
|
||||
{
|
||||
int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
if (PixelSize == 1)
|
||||
{
|
||||
ColorPalette cp = clone.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
}
|
||||
clone.Palette = cp;
|
||||
}
|
||||
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat);
|
||||
|
||||
int depth_width = source_bitmap.Width * PixelSize;
|
||||
|
||||
unsafe
|
||||
{
|
||||
byte* source_ptr = (byte*)source_bitmap.Scan0;
|
||||
byte* destination_ptr = (byte*)destination_bitmap.Scan0;
|
||||
|
||||
int offset = source_bitmap.Stride - depth_width;
|
||||
|
||||
for (int i = 0; i < source_bitmap.Height; i++)
|
||||
{
|
||||
for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++)
|
||||
{
|
||||
*destination_ptr = *source_ptr;
|
||||
}
|
||||
|
||||
source_ptr += offset;
|
||||
destination_ptr += offset;
|
||||
}
|
||||
}
|
||||
|
||||
source.UnlockBits(source_bitmap);
|
||||
clone.UnlockBits(destination_bitmap);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2)
|
||||
{
|
||||
Bitmap connectImage = null;
|
||||
if (map1 == null || map2 == null)
|
||||
return null;
|
||||
//横向拼接
|
||||
int width = map1.Width + map2.Width;
|
||||
//高度不变
|
||||
int height = Math.Max(map1.Height, map2.Height);
|
||||
connectImage = new Bitmap(width, height);
|
||||
using (Graphics graph = Graphics.FromImage(connectImage))
|
||||
{
|
||||
graph.DrawImage(connectImage, width, height);
|
||||
graph.Clear(System.Drawing.Color.White);
|
||||
graph.DrawImage(map1, 0, 0);
|
||||
graph.DrawImage(map2, map1.Width, 0);
|
||||
}
|
||||
return connectImage;
|
||||
}
|
||||
|
||||
public static IntPtr FloatToIntptr(float[] bytes)
|
||||
{
|
||||
GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
return hObject.AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
// 将Btimap类转换为byte[]类函数
|
||||
public static byte[] GetBGRValues(Bitmap bmp, out int stride)
|
||||
{
|
||||
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
||||
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
||||
stride = bmpData.Stride;
|
||||
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
|
||||
var imgBytes = bmp.Height * rowBytes;
|
||||
byte[] rgbValues = new byte[imgBytes];
|
||||
IntPtr ptr = bmpData.Scan0;
|
||||
for (var i = 0; i < bmp.Height; i++)
|
||||
{
|
||||
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
|
||||
ptr += bmpData.Stride;
|
||||
}
|
||||
bmp.UnlockBits(bmpData);
|
||||
return rgbValues;
|
||||
}
|
||||
/// <summary>
|
||||
/// 缺陷灰度图转彩色图像函数
|
||||
/// </summary>
|
||||
/// <param name="src">灰度图</param>
|
||||
/// <returns>返回构造的伪彩色图像</returns>
|
||||
public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Stopwatch sw = new Stopwatch();
|
||||
//sw.Start();
|
||||
|
||||
Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
|
||||
|
||||
int destHeight = dest.Height;
|
||||
int destWidth = dest.Width;
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, destWidth, destHeight);
|
||||
BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||
int strideDest = bmpDataDest.Stride;
|
||||
|
||||
int strideSrc = bmpDataSrc.Stride;
|
||||
unsafe
|
||||
{
|
||||
byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer();
|
||||
byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer();
|
||||
|
||||
Parallel.For(0, destHeight, y =>
|
||||
{
|
||||
Parallel.For(0, destWidth, x =>
|
||||
{
|
||||
int pixel = pSrc[y * strideSrc + x];
|
||||
int startIndex = y * strideDest + x * 4;
|
||||
if (pixel >= 0 && pixel <= 63)
|
||||
{
|
||||
Color color = Color.Red;
|
||||
if (indexColorDict != null && indexColorDict.ContainsKey(pixel))
|
||||
{
|
||||
color = indexColorDict[pixel];
|
||||
}
|
||||
|
||||
byte R = color.R;
|
||||
byte G = color.G;
|
||||
byte B = color.B;
|
||||
|
||||
pDest[startIndex] = B;
|
||||
pDest[startIndex + 1] = G;
|
||||
pDest[startIndex + 2] = R;
|
||||
pDest[startIndex + 3] = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDest[startIndex] = 255;
|
||||
pDest[startIndex + 1] = 255;
|
||||
pDest[startIndex + 2] = 255;
|
||||
pDest[startIndex + 3] = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
dest.UnlockBits(bmpDataDest);
|
||||
src.UnlockBits(bmpDataSrc);
|
||||
|
||||
//sw.Stop();
|
||||
//Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}");
|
||||
|
||||
return dest;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T>
|
||||
{
|
||||
List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序
|
||||
for (int i = 0; i < sortedList.Count(); i++)
|
||||
{
|
||||
collection.Move(collection.IndexOf(sortedList[i]), i);
|
||||
}
|
||||
}
|
||||
|
||||
// 布尔类型转换为整型
|
||||
public static int ToInt(this object obj)
|
||||
{
|
||||
if (Convert.ToBoolean(obj) == true)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 整型转换为布尔类型
|
||||
public static bool ToBool(this object obj)
|
||||
{
|
||||
if (Convert.ToInt32(obj) == 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static object GetProperty(this object o, string member)
|
||||
{
|
||||
if (o == null) throw new ArgumentNullException("o");
|
||||
if (member == null) throw new ArgumentNullException("member");
|
||||
Type scope = o.GetType();
|
||||
IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
|
||||
if (provider != null)
|
||||
{
|
||||
ParameterExpression param = Expression.Parameter(typeof(object));
|
||||
DynamicMetaObject mobj = provider.GetMetaObject(param);
|
||||
GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
|
||||
DynamicMetaObject ret = mobj.BindGetMember(binder);
|
||||
BlockExpression final = Expression.Block(
|
||||
Expression.Label(CallSiteBinder.UpdateLabel),
|
||||
ret.Expression
|
||||
);
|
||||
LambdaExpression lambda = Expression.Lambda(final, param);
|
||||
Delegate del = lambda.Compile();
|
||||
return del.DynamicInvoke(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
|
||||
}
|
||||
}
|
||||
|
||||
#region 检测文件状态及操作方式选择
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool CloseHandle(IntPtr hObject);
|
||||
private const int OF_READWRITE = 2;
|
||||
private const int OF_SHARE_DENY_NONE = 0x40;
|
||||
private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
|
||||
/// <summary>
|
||||
/// 检测文件是否只读或被使用
|
||||
/// </summary>
|
||||
/// <param name="FileNames">要检测的文件</param>
|
||||
/// <returns>true可用,false在用或只读</returns>
|
||||
public static bool CheckFilesCanUse(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
return true;//文件不存在
|
||||
if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||
return false; //文件只读
|
||||
IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE);
|
||||
if (vHandle == HFILE_ERROR)
|
||||
{
|
||||
CloseHandle(vHandle);
|
||||
return false; //文件被占用
|
||||
}
|
||||
|
||||
CloseHandle(vHandle); //文件没被占用
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有的文件名称
|
||||
/// </summary>
|
||||
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||
/// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param>
|
||||
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||
public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false)
|
||||
{
|
||||
List<FileInfo> resList = new List<FileInfo>();
|
||||
try
|
||||
{
|
||||
DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录
|
||||
FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件
|
||||
foreach (FileInfo file in currFiles)
|
||||
{
|
||||
if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0)
|
||||
{
|
||||
resList.Add(file);
|
||||
}
|
||||
}
|
||||
if (isContainSubFolder)
|
||||
{
|
||||
string[] subFolders = Directory.GetDirectories(folderName);
|
||||
foreach (string subFolder in subFolders)
|
||||
{
|
||||
resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
return resList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有的文件名称,不过滤文件类型
|
||||
/// </summary>
|
||||
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||
public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder)
|
||||
{
|
||||
return GetAllFilesByFolder(folderName, "*", isContainSubFolder);
|
||||
}
|
||||
}
|
||||
|
||||
public class Compare<T, C> : IEqualityComparer<T>
|
||||
{
|
||||
private Func<T, C> _getField;
|
||||
public Compare(Func<T, C> getfield)
|
||||
{
|
||||
_getField = getfield;
|
||||
}
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));
|
||||
}
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
return EqualityComparer<C>.Default.GetHashCode(_getField(obj));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
|
||||
{
|
||||
return source.Distinct(new Compare<T, C>(getfield));
|
||||
}
|
||||
|
||||
public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield)
|
||||
{
|
||||
return source.Distinct(new Compare<T, C>(getfield));
|
||||
}
|
||||
}
|
||||
}
|
72
src/BRS.Common.Model/Helper/TimeOutHelper.cs
Normal file
72
src/BRS.Common.Model/Helper/TimeOutHelper.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System.Threading;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public delegate void OnTimeoutDelegate();
|
||||
public class TimeOutHelper
|
||||
{
|
||||
private const int TIMEINTERVAL = 1000;
|
||||
private bool isPause = false;
|
||||
int timeTick = 0;
|
||||
|
||||
public event OnTimeoutDelegate OnTimeout;
|
||||
|
||||
public Timer MonitorTimer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超时最大时间,以秒为单位
|
||||
/// </summary>
|
||||
public int MaxLimit { get; set; } = 250;
|
||||
|
||||
public TimeOutHelper()
|
||||
{
|
||||
InitialTimer();
|
||||
}
|
||||
|
||||
private void InitialTimer()
|
||||
{
|
||||
MonitorTimer = new Timer(new TimerCallback(OnTimeTick), null, Timeout.Infinite, TIMEINTERVAL);
|
||||
}
|
||||
|
||||
private void OnTimeTick(object state)
|
||||
{
|
||||
if (!isPause)
|
||||
{
|
||||
timeTick++;
|
||||
}
|
||||
|
||||
if (timeTick >= MaxLimit)
|
||||
{
|
||||
OnTimeout?.Invoke();
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public TimeOutHelper(int limit)
|
||||
{
|
||||
MaxLimit = limit;
|
||||
InitialTimer();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
timeTick = 0;
|
||||
MonitorTimer.Change(0, TIMEINTERVAL);
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
isPause = true;
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
isPause = false;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
MonitorTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
123
src/BRS.Common.Model/Helper/UIHelper.cs
Normal file
123
src/BRS.Common.Model/Helper/UIHelper.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public static class UIHelper
|
||||
{
|
||||
public static void SetCombo(ComboBox cbo, object dataSource, string display, string value)
|
||||
{
|
||||
cbo.DataSource = dataSource;
|
||||
cbo.DisplayMember = display;
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
cbo.ValueMember = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCombo(ToolStripComboBox cbo, object dataSource, string display, string value)
|
||||
{
|
||||
cbo.ComboBox.DataSource = dataSource;
|
||||
cbo.ComboBox.DisplayMember = display;
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
cbo.ComboBox.ValueMember = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCombo(DataGridViewComboBoxColumn cbo, object dataSource, string display, string value)
|
||||
{
|
||||
cbo.DataSource = dataSource;
|
||||
cbo.DisplayMember = display;
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
cbo.ValueMember = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region DataGridView设置列头为复选框
|
||||
public class DataGridViewCheckboxHeaderEventArgs : EventArgs
|
||||
{
|
||||
private bool checkedState = false;
|
||||
|
||||
public bool CheckedState
|
||||
{
|
||||
get { return checkedState; }
|
||||
set { checkedState = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void DataGridViewCheckboxHeaderEventHander(object sender, DataGridViewCheckboxHeaderEventArgs e);
|
||||
public class DataGridViewCheckboxHeaderCell : DataGridViewColumnHeaderCell
|
||||
{
|
||||
Point checkBoxLocation;
|
||||
Size checkBoxSize;
|
||||
bool _checked = false;
|
||||
Point _cellLocation = new Point();
|
||||
System.Windows.Forms.VisualStyles.CheckBoxState _cbState = System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
|
||||
|
||||
public event DataGridViewCheckboxHeaderEventHander OnCheckBoxClicked;
|
||||
|
||||
//绘制列头checkbox
|
||||
protected override void Paint(System.Drawing.Graphics graphics,
|
||||
System.Drawing.Rectangle clipBounds,
|
||||
System.Drawing.Rectangle cellBounds,
|
||||
int rowIndex,
|
||||
DataGridViewElementStates dataGridViewElementState,
|
||||
object value,
|
||||
object formattedValue,
|
||||
string errorText,
|
||||
DataGridViewCellStyle cellStyle,
|
||||
DataGridViewAdvancedBorderStyle advancedBorderStyle,
|
||||
DataGridViewPaintParts paintParts)
|
||||
{
|
||||
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
|
||||
dataGridViewElementState, value,
|
||||
formattedValue, errorText, cellStyle,
|
||||
advancedBorderStyle, paintParts);
|
||||
|
||||
Point p = new Point();
|
||||
Size s = CheckBoxRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
|
||||
p.X = cellBounds.Location.X + (cellBounds.Width / 2) - (s.Width / 2) - 1; //列头checkbox的X坐标
|
||||
p.Y = cellBounds.Location.Y + (cellBounds.Height / 2) - (s.Height / 2); //列头checkbox的Y坐标
|
||||
_cellLocation = cellBounds.Location;
|
||||
checkBoxLocation = p;
|
||||
checkBoxSize = s;
|
||||
if (_checked)
|
||||
_cbState = System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal;
|
||||
else
|
||||
_cbState = System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
|
||||
|
||||
CheckBoxRenderer.DrawCheckBox(graphics, checkBoxLocation, _cbState);
|
||||
}
|
||||
|
||||
///
|
||||
/// 点击列头checkbox单击事件
|
||||
///
|
||||
protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
|
||||
{
|
||||
Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
|
||||
if (p.X >= checkBoxLocation.X && p.X <= checkBoxLocation.X + checkBoxSize.Width
|
||||
&& p.Y >= checkBoxLocation.Y && p.Y <= checkBoxLocation.Y + checkBoxSize.Height)
|
||||
{
|
||||
_checked = !_checked;
|
||||
|
||||
//获取列头checkbox的选择状态
|
||||
DataGridViewCheckboxHeaderEventArgs ex = new DataGridViewCheckboxHeaderEventArgs();
|
||||
ex.CheckedState = _checked;
|
||||
|
||||
object sender = new object();//此处不代表选择的列头checkbox,只是作为参数传递。因为列头checkbox是绘制出来的,无法获得它的实例
|
||||
|
||||
if (OnCheckBoxClicked != null)
|
||||
{
|
||||
OnCheckBoxClicked(sender, ex);//触发单击事件
|
||||
DataGridView.InvalidateCell(this);
|
||||
}
|
||||
}
|
||||
base.OnMouseClick(e);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
100
src/BRS.Common.Model/Helper/WebApiHelper.cs
Normal file
100
src/BRS.Common.Model/Helper/WebApiHelper.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class WebApiHelper
|
||||
{
|
||||
//以毫秒为单位
|
||||
readonly int TimeOut = 999999999;
|
||||
|
||||
public WebApiHelper(int timeout = 9999999)
|
||||
{
|
||||
TimeOut = timeout;
|
||||
}
|
||||
|
||||
public async Task<string> dooPostAsync(string actionUrl, string paras)
|
||||
{
|
||||
string responseStr = string.Empty;
|
||||
|
||||
WebRequest request = WebRequest.Create(actionUrl);
|
||||
request.Timeout = TimeOut;
|
||||
//request.Headers.Add("Authorization", "SDXK_Service");
|
||||
request.Method = "Post";
|
||||
request.ContentType = "application/json";
|
||||
|
||||
byte[] requestData = System.Text.Encoding.UTF8.GetBytes(paras);
|
||||
request.ContentLength = requestData.Length;
|
||||
|
||||
Stream newStream = request.GetRequestStream();
|
||||
newStream.Write(requestData, 0, requestData.Length);
|
||||
newStream.Close();
|
||||
|
||||
var response = await request.GetResponseAsync();
|
||||
Stream ReceiveStream = response.GetResponseStream();
|
||||
using (StreamReader stream = new StreamReader(ReceiveStream, Encoding.UTF8))
|
||||
{
|
||||
responseStr = stream.ReadToEnd();
|
||||
}
|
||||
|
||||
return responseStr;
|
||||
}
|
||||
|
||||
/// <summary></summary>
|
||||
/// <param name="actionUrl"></param>
|
||||
/// <param name="content">
|
||||
/// var content = new FormUrlEncodedContent(new Dictionary<string, string>()
|
||||
///{
|
||||
/// { "","AEADDE34"}
|
||||
///});
|
||||
///</param>
|
||||
/// <returns></returns>
|
||||
public string dooPost(string actionUrl, HttpContent content)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.Timeout = new TimeSpan(0, 0, TimeOut / 1000);
|
||||
//httpClient.DefaultRequestHeaders.Add("Authorization", "SDXK_Service");
|
||||
|
||||
return httpClient.PostAsync(actionUrl, content)
|
||||
.Result.Content.ReadAsStringAsync().Result;
|
||||
}
|
||||
|
||||
public string dooPost(string actionUrl, string paras)
|
||||
{
|
||||
string responseStr = string.Empty;
|
||||
|
||||
WebRequest request = WebRequest.Create(actionUrl);
|
||||
request.Timeout = TimeOut;
|
||||
//request.Headers.Add("Authorization", "SDXK_Service");
|
||||
request.Method = "Post";
|
||||
request.ContentType = "application/json";
|
||||
|
||||
byte[] requestData = System.Text.Encoding.UTF8.GetBytes(paras);
|
||||
request.ContentLength = requestData.Length;
|
||||
|
||||
Stream newStream = request.GetRequestStream();
|
||||
newStream.Write(requestData, 0, requestData.Length);
|
||||
newStream.Close();
|
||||
|
||||
var response = request.GetResponse();
|
||||
Stream ReceiveStream = response.GetResponseStream();
|
||||
using (StreamReader stream = new StreamReader(ReceiveStream, Encoding.UTF8))
|
||||
{
|
||||
responseStr = stream.ReadToEnd();
|
||||
}
|
||||
|
||||
return responseStr;
|
||||
}
|
||||
|
||||
public string dooGet(string actionUrl)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.Timeout = new TimeSpan(0, 0, TimeOut / 1000);
|
||||
return httpClient.GetAsync(actionUrl).Result.Content.ReadAsStringAsync().Result;
|
||||
}
|
||||
}
|
||||
}
|
98
src/BRS.Common.Model/Helper/WebServiceHelper.cs
Normal file
98
src/BRS.Common.Model/Helper/WebServiceHelper.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using System.Web.Services.Description;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace BRS.Common.Model.Helper
|
||||
{
|
||||
public class WebServiceHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成dll文件保存到本地
|
||||
/// </summary>
|
||||
/// <param name="url">WebService地址</param>
|
||||
/// <param name="className">类名</param>
|
||||
/// <param name="methodName">方法名</param>
|
||||
/// <param name="filePath">保存dll文件的路径</param>
|
||||
public static void CreateWebServiceDLL(string url, string className, string methodName, string filePath)
|
||||
{
|
||||
// 1. 使用 WebClient 下载 WSDL 信息。
|
||||
WebClient web = new WebClient();
|
||||
Stream stream = web.OpenRead(url + "?wsdl");
|
||||
// 2. 创建和格式化 WSDL 文档。
|
||||
ServiceDescription description = ServiceDescription.Read(stream);
|
||||
//如果不存在就创建file文件夹
|
||||
if (Directory.Exists(filePath) == false)
|
||||
{
|
||||
Directory.CreateDirectory(filePath);
|
||||
}
|
||||
|
||||
if (File.Exists(filePath + className + "_" + methodName + ".dll"))
|
||||
{
|
||||
//判断缓存是否过期
|
||||
var cachevalue = HttpRuntime.Cache.Get(className + "_" + methodName);
|
||||
if (cachevalue == null)
|
||||
{
|
||||
//缓存过期删除dll
|
||||
File.Delete(filePath + className + "_" + methodName + ".dll");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果缓存没有过期直接返回
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 创建客户端代理代理类。
|
||||
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
|
||||
// 指定访问协议。
|
||||
importer.ProtocolName = "Soap";
|
||||
// 生成客户端代理。
|
||||
importer.Style = ServiceDescriptionImportStyle.Client;
|
||||
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
|
||||
// 添加 WSDL 文档。
|
||||
importer.AddServiceDescription(description, null, null);
|
||||
// 4. 使用 CodeDom 编译客户端代理类。
|
||||
// 为代理类添加命名空间,缺省为全局空间。
|
||||
CodeNamespace nmspace = new CodeNamespace();
|
||||
CodeCompileUnit unit = new CodeCompileUnit();
|
||||
unit.Namespaces.Add(nmspace);
|
||||
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
|
||||
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
|
||||
CompilerParameters parameter = new CompilerParameters();
|
||||
parameter.GenerateExecutable = false;
|
||||
// 可以指定你所需的任何文件名。
|
||||
parameter.OutputAssembly = filePath + className + "_" + methodName + ".dll";
|
||||
parameter.ReferencedAssemblies.Add("System.dll");
|
||||
parameter.ReferencedAssemblies.Add("System.XML.dll");
|
||||
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
|
||||
parameter.ReferencedAssemblies.Add("System.Data.dll");
|
||||
// 生成dll文件,并会把WebService信息写入到dll里面
|
||||
CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
|
||||
if (result.Errors.HasErrors)
|
||||
{
|
||||
// 显示编译错误信息
|
||||
System.Text.StringBuilder sb = new StringBuilder();
|
||||
foreach (CompilerError ce in result.Errors)
|
||||
{
|
||||
sb.Append(ce.ToString());
|
||||
sb.Append(System.Environment.NewLine);
|
||||
}
|
||||
throw new Exception(sb.ToString());
|
||||
}
|
||||
//记录缓存
|
||||
var objCache = HttpRuntime.Cache;
|
||||
// 缓存信息写入dll文件
|
||||
objCache.Insert(className + "_" + methodName, "1", null, DateTime.Now.AddMinutes(5), TimeSpan.Zero, CacheItemPriority.High, null);
|
||||
}
|
||||
}
|
||||
}
|
9
src/BRS.Common.Model/Interface/ICSVOutput.cs
Normal file
9
src/BRS.Common.Model/Interface/ICSVOutput.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface ICSVOutput
|
||||
{
|
||||
string GetCSVHead();
|
||||
|
||||
string GetCSVData();
|
||||
}
|
||||
}
|
14
src/BRS.Common.Model/Interface/IConfigCtrl.cs
Normal file
14
src/BRS.Common.Model/Interface/IConfigCtrl.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
//public delegate void ConfigChangedDelegate();
|
||||
public interface IConfigCtrl<T1, T2>
|
||||
{
|
||||
//event ConfigChangedDelegate OnConfigChanged;
|
||||
T1 Camera { get; set; }
|
||||
T2 Config { get; set; }
|
||||
|
||||
void LoadConfig(T2 t);
|
||||
|
||||
T2 GetConfig();
|
||||
}
|
||||
}
|
44
src/BRS.Common.Model/Interface/IDevice.cs
Normal file
44
src/BRS.Common.Model/Interface/IDevice.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using BRS.Common.Model;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IDevice : IDisposable, INotifyPropertyChanged, ISimpleDevice, ILogger, IExceptionHandler
|
||||
{
|
||||
IInitialConfig InitialConfig { get; set; }
|
||||
|
||||
EnumHelper.DeviceState CurrentState { get; set; }
|
||||
event Action<IDevice, DeviceState> OnDeviceStateChanged;
|
||||
|
||||
void StateChange(EnumHelper.DeviceState stateToBe);
|
||||
|
||||
ResponseMessage RunWrap(IOperationConfig opConfig);
|
||||
}
|
||||
|
||||
public interface ISimpleDevice
|
||||
{
|
||||
string Id { get; set; }
|
||||
string Name { get; set; }
|
||||
}
|
||||
|
||||
public class SimpleDevice : ISimpleDevice
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用来记录配置中设备信息的接口
|
||||
/// </summary>
|
||||
public interface ISourceDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备信息编号
|
||||
/// </summary>
|
||||
string SourceDeviceId { get; set; }
|
||||
}
|
||||
}
|
41
src/BRS.Common.Model/Interface/IDeviceConfig.cs
Normal file
41
src/BRS.Common.Model/Interface/IDeviceConfig.cs
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备配置
|
||||
/// </summary>
|
||||
public interface IDeviceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 暂时设想的一些不好归类的配置,使用json序列化之后保存在该字段
|
||||
/// </summary>
|
||||
//string DataConfig { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备初始配置
|
||||
/// </summary>
|
||||
public interface IInitialConfig : ILogConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备序号 GUID
|
||||
/// 因为本项目设备信息未做配置,将索引添加在初始配置中
|
||||
/// </summary>
|
||||
string Id { get; set; }
|
||||
|
||||
string Name { get; set; }
|
||||
|
||||
bool IsEnabled { get; set; }
|
||||
|
||||
string DriverType { get; set; }
|
||||
}
|
||||
|
||||
public interface ILogConfig
|
||||
{
|
||||
string LogPath { get; set; }
|
||||
|
||||
bool IsEnableLog { get; set; }
|
||||
bool IsEnableCSV { get; set; }
|
||||
}
|
||||
}
|
9
src/BRS.Common.Model/Interface/IHalconToolPath.cs
Normal file
9
src/BRS.Common.Model/Interface/IHalconToolPath.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IHalconToolPath
|
||||
{
|
||||
List<string> GetHalconToolPathList();
|
||||
}
|
||||
}
|
14
src/BRS.Common.Model/Interface/IIOModuleConfig.cs
Normal file
14
src/BRS.Common.Model/Interface/IIOModuleConfig.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IIOModuleConfig
|
||||
{
|
||||
List<IODefinition> IODefinitionCollection { get; set; }
|
||||
}
|
||||
}
|
242
src/BRS.Common.Model/Interface/IImageSet.cs
Normal file
242
src/BRS.Common.Model/Interface/IImageSet.cs
Normal file
@ -0,0 +1,242 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using OpenCvSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 所有图片类型的基类
|
||||
/// </summary>
|
||||
public abstract class BaseImage : object, IDisposable
|
||||
{
|
||||
public abstract int Width { get; }
|
||||
public abstract int Height { get; }
|
||||
|
||||
public abstract Mat Mat();
|
||||
|
||||
public abstract BaseImage Clone();
|
||||
public abstract void Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// 转换为Bitmap对象并返回
|
||||
/// </summary>
|
||||
/// <returns>返回转换后的Bitmap对象,可以在子类种自行做缓存</returns>
|
||||
public abstract Bitmap ConvertToBitmap();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T">图片类型范围</typeparam>
|
||||
public interface IImageSet : IDisposable
|
||||
{
|
||||
string Id { get; set; }
|
||||
string CameraId { get; set; }
|
||||
BaseImage BImage { get; set; }
|
||||
Bitmap Image { get; set; }
|
||||
DateTime ImageTime { get; set; }
|
||||
string PId { get; set; }
|
||||
string Prefix { get; set; }
|
||||
|
||||
object SaveLock { get; set; }
|
||||
|
||||
ImageSaveOption ImageSaveOption { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 序列化操作的图像信息
|
||||
/// </summary>
|
||||
string ImageData { get; set; }
|
||||
|
||||
void SaveImage();
|
||||
|
||||
// Bitmap ConvertTImageToBitmap(TImg img);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class ImageSaveOption : IComplexDisplay
|
||||
{
|
||||
[Category("启用配置")]
|
||||
[Description("是否启用")]
|
||||
[DisplayName("是否启用")]
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
|
||||
[Category("图片保存")]
|
||||
[Description("图片保存文件夹")]
|
||||
[DisplayName("图片保存文件夹")]
|
||||
public virtual string ImageSaveDirectory { get; set; }
|
||||
|
||||
[Category("图片保存")]
|
||||
[Description("图片保存格式")]
|
||||
[DisplayName("图片保存格式")]
|
||||
public ImageFormat ImageFormat { get; set; } = ImageFormat.Png;
|
||||
|
||||
|
||||
|
||||
public ImageSaveOption Copy()
|
||||
{
|
||||
ImageSaveOption iso = new ImageSaveOption();
|
||||
iso.ImageSaveDirectory = this.ImageSaveDirectory;
|
||||
iso.ImageFormat = this.ImageFormat;
|
||||
iso.IsEnabled = this.IsEnabled;
|
||||
|
||||
return iso;
|
||||
}
|
||||
|
||||
public string GetDisplayText()
|
||||
{
|
||||
string txt = IsEnabled ? "启用:" : "禁用";
|
||||
if (!string.IsNullOrWhiteSpace(ImageSaveDirectory))
|
||||
{
|
||||
txt += $"目录:{ImageSaveDirectory}";
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
|
||||
public class VisionImageSaveOption : ImageSaveOption
|
||||
{
|
||||
//[Category("图片保存")]
|
||||
//[Description("true:产品模式,同一个产品 不同工站 处理完的的图片,会保存在同一个产品文件夹下;false:检测工站模式,处理完的图片会以 RawImages、PreTreatedImages、PreTreatedAnalysisImages...等路径保存")]
|
||||
//[DisplayName("是否产品模式")]
|
||||
//public bool IsProductModel { get; set; } = false;
|
||||
|
||||
[Category("图片保存")]
|
||||
[Description("是否保存原始检测图片")]
|
||||
[DisplayName("保存原始检测图片")]
|
||||
public bool IsSaveDetectionOriginImage { get; set; } = false;
|
||||
|
||||
|
||||
[Category("图片保存")]
|
||||
[Description("是否保存结果图片")]
|
||||
[DisplayName("保存结果图片")]
|
||||
public bool IsSaveFitImage { get; set; } = false;
|
||||
|
||||
[Category("图片保存")]
|
||||
[Description("检测结果附加保存类型,针对检测完的结果保存图片,多类型使用\",\"间隔。如要保存OK和NG 裂纹 图片,填写\"OK,NG,裂纹\"")]
|
||||
[DisplayName("检测结果附加保存类型")]
|
||||
public string AddtionalSaveType { get; set; } = "NG";
|
||||
|
||||
[Browsable(false)]
|
||||
public override string ImageSaveDirectory { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class ImageSet : IImageSet
|
||||
{
|
||||
// public virtual Bitmap ConvertTImageToBitmap(TImg img) { return null; }
|
||||
|
||||
public DateTime ImageTime { get; set; } = DateTime.Now;
|
||||
|
||||
private string id = "";
|
||||
public string Id
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
id = ImageTime.ToString("HHmmssfff");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
set
|
||||
{
|
||||
id = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string CameraId { get; set; }
|
||||
|
||||
public string Prefix { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 原图 HImage
|
||||
/// </summary>
|
||||
public BaseImage BImage { get; set; } = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 原图 Bitmap
|
||||
/// </summary>
|
||||
public Bitmap Image { get; set; } = null;
|
||||
|
||||
|
||||
public string PId { get; set; }
|
||||
|
||||
#region Save Option & Result
|
||||
public virtual ImageSaveOption ImageSaveOption { get; set; } = new ImageSaveOption();
|
||||
|
||||
public bool IsSaveOrigin { get; set; } = false;
|
||||
public object SaveLock { get; set; } = new object();
|
||||
public virtual string ImageData { get; set; }
|
||||
|
||||
public virtual void SaveImage()
|
||||
{
|
||||
if (IsSaveOrigin)
|
||||
{
|
||||
string imageDir = string.IsNullOrWhiteSpace(Prefix) ? DateTime.Now.ToString("yyyyMMdd") : Path.Combine(Prefix, DateTime.Now.ToString("yyyyMMdd"));
|
||||
string filename = string.IsNullOrWhiteSpace(Prefix) ? $"{Id}.{ImageSaveOption.ImageFormat.ToString().ToLower()}" : $"{Prefix}_{Id}.{ImageSaveOption.ImageFormat.ToString().ToLower()}";
|
||||
string filePath = Path.Combine(ImageSaveOption.ImageSaveDirectory, imageDir, filename);
|
||||
Image.Save(filePath, ImageSaveOption.ImageFormat);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Image?.Dispose();
|
||||
Image = null;
|
||||
|
||||
BImage?.Dispose();
|
||||
BImage = null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class DualImageSet : ImageSet
|
||||
{
|
||||
public BaseImage HImage_2 { get; set; }
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
HImage_2?.Dispose();
|
||||
HImage_2 = null;
|
||||
}
|
||||
|
||||
public override void SaveImage()
|
||||
{
|
||||
//if (string.IsNullOrWhiteSpace(imageName))
|
||||
//{
|
||||
// imageName = Id;
|
||||
//}
|
||||
|
||||
//string filePath = "";
|
||||
//if (image != null)
|
||||
//{
|
||||
// filePath = Path.Combine(imageDir, $"{imageName}.{ImageSaveOption.ImageFormat.ToString().ToLower()}");
|
||||
// image.Save(filePath, ImageSaveOption.ImageFormat);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// filePath = Path.Combine(imageDir, $"{imageName}.tif");
|
||||
// HImage_2.WriteImage("tiff", 0, filePath);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
50
src/BRS.Common.Model/Interface/IInputConfig.cs
Normal file
50
src/BRS.Common.Model/Interface/IInputConfig.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备的实际运行的硬件输入配置
|
||||
/// 考虑使用消息接收机制在这里等待外部信号进入
|
||||
/// </summary>
|
||||
public interface IInputConfig : IDisposable //: IProcessID
|
||||
{
|
||||
/// <summary>
|
||||
/// 该配置对应的工序编号
|
||||
/// 考虑到多工序可能对应到同样的配置,工序编号不做固定赋值,在设备运作时随用随赋值
|
||||
/// </summary>
|
||||
string ProcessId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 工序名称
|
||||
/// </summary>
|
||||
string ProcessName { get; set; }
|
||||
|
||||
//Dictionary<string, AutoResetEvent> InputHanlderDict { get; set; }
|
||||
//Dictionary<string, bool> InputFlagDict { get; set; }
|
||||
|
||||
//ConcurrentDictionary<string, AutoResetEvent> InputHanlderDict { get; set; }
|
||||
|
||||
//ConcurrentDictionary<string, bool> InputFlagDict { get; set; }
|
||||
|
||||
AutoResetEvent InputHandle { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 是否已进入输入配置方法标志
|
||||
///// </summary>
|
||||
//bool BoundFlag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要做硬输入(外部输入)判断 false:不需要 true:需要
|
||||
/// </summary>
|
||||
bool IsInputNeed { get; set; }
|
||||
|
||||
string InputMethodName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 第三方设备输入参数
|
||||
/// </summary>
|
||||
dynamic InputPara { get; set; }
|
||||
}
|
||||
}
|
14
src/BRS.Common.Model/Interface/ILogger.cs
Normal file
14
src/BRS.Common.Model/Interface/ILogger.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface ILogger
|
||||
{
|
||||
event Action<LogMsg> OnLog;
|
||||
LoggerHelper LoggerHelper { get; set; }
|
||||
//void LogAsync(DateTime dt, LogLevel loglevel, string msg);
|
||||
void LogAsync(LogMsg msg);
|
||||
}
|
||||
}
|
49
src/BRS.Common.Model/Interface/IMenuNode.cs
Normal file
49
src/BRS.Common.Model/Interface/IMenuNode.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IMenuNode
|
||||
{
|
||||
// IProcess Process { get; set; }
|
||||
|
||||
//void DownloadProcess(IProcess process);
|
||||
//Action<IProcess> OnUploadProcess { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public interface IClickableMenuNode : IMenuNode
|
||||
{
|
||||
IProcess Process { get; set; }
|
||||
void OnClick(IProcess process);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public interface IProcessObserver
|
||||
{
|
||||
IProcess Process { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 流程更新时回调函数
|
||||
/// </summary>
|
||||
void OnProcessUpdated();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 加载流程
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
void DownloadProcess(IProcess process);
|
||||
}
|
||||
|
||||
public interface ILogOutput
|
||||
{
|
||||
event Action<LogMsg> OnLogMsgOutput;
|
||||
void LogDisplay(LogMsg msg);
|
||||
}
|
||||
}
|
16
src/BRS.Common.Model/Interface/IMonitor.cs
Normal file
16
src/BRS.Common.Model/Interface/IMonitor.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
//public delegate void OnMonitorInvokeDelegate(DateTime dt, string invokeDeviceId, IDevice sourceDevice, MonitorSet monitorSet);
|
||||
//public delegate void OnMonitorAlarmDelegate(DateTime dt, IDevice device, WarningSet warning);
|
||||
public interface IMonitor
|
||||
{
|
||||
void Monitor();
|
||||
void ResetAlarm();
|
||||
|
||||
Action<DateTime, string, IDevice, IMonitorSet> OnMonitorInvoke { get; set; }
|
||||
Action<DateTime, IDevice, IWarningSet> OnMonitorAlarm { get; set; }
|
||||
}
|
||||
}
|
48
src/BRS.Common.Model/Interface/IMonitorSetCollection.cs
Normal file
48
src/BRS.Common.Model/Interface/IMonitorSetCollection.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using BRS.Common.Model;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IMonitorSetCollection
|
||||
{
|
||||
//List<IMonitorSet> MonitorSetCollection { get; set; }
|
||||
|
||||
List<IMonitorSet> GetAllMonitorSet();
|
||||
}
|
||||
|
||||
public interface IMonitorConfig : IMonitorSetCollection
|
||||
{
|
||||
bool IsEnableMonitor { get; set; }
|
||||
|
||||
int MonitorInterval { get; set; }
|
||||
|
||||
int MonitorTimeout { get; set; }
|
||||
}
|
||||
|
||||
public interface IMonitorSet : ISourceDevice
|
||||
{
|
||||
string Id { get; set; }
|
||||
|
||||
string ExecuteDevice { get; set; }
|
||||
|
||||
string MethodCode { get; set; }
|
||||
|
||||
string MethodDesc { get; }
|
||||
|
||||
IOperationConfig OpConfig { get; set; }
|
||||
|
||||
//int TriggerIndex { get; set; }
|
||||
|
||||
//int TriggerValue { get; set; }
|
||||
|
||||
string Name { get; set; }
|
||||
|
||||
string DisplayText { get; }
|
||||
|
||||
//string SourceDeviceId { get; set; }
|
||||
|
||||
ResponseMessage Response { get; set; }
|
||||
|
||||
bool IsOriginOutput { get; set; }
|
||||
}
|
||||
}
|
42
src/BRS.Common.Model/Interface/IOperationConfig.cs
Normal file
42
src/BRS.Common.Model/Interface/IOperationConfig.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作配置
|
||||
/// </summary>
|
||||
public interface IOperationConfig //: IOperationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 发生异常时的重新尝试次数
|
||||
/// </summary>
|
||||
int ReTryTimes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 输入参数
|
||||
/// </summary>
|
||||
List<int> InputPara { get; set; }
|
||||
|
||||
int TriggerValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当异常发生时的异常反馈值
|
||||
/// </summary>
|
||||
int ExceptionValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指示该操作的监视配置来源
|
||||
/// </summary>
|
||||
string MonitorSetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 调用该操作配置的设备Id
|
||||
/// </summary>
|
||||
string ExecuteDeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作执行后部分输出结果,目前拟采用序列化后的字符串方式保存
|
||||
/// </summary>
|
||||
string OutputData { get; set; }
|
||||
}
|
||||
}
|
43
src/BRS.Common.Model/Interface/IOperationResult.cs
Normal file
43
src/BRS.Common.Model/Interface/IOperationResult.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Bro.Common.Helper;
|
||||
|
||||
namespace Bro.Common.Interface
|
||||
{
|
||||
public interface IOperationResult //: IProcessID
|
||||
{
|
||||
///// <summary>
|
||||
///// 该配置对应的工序编号
|
||||
///// 考虑到多工序可能对应到同样的配置,工序编号不做固定赋值,在设备运作时随用随赋值
|
||||
///// </summary>
|
||||
//string ProcessId { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 工序名称
|
||||
///// </summary>
|
||||
//string ProcessName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结果输出 具体结果参照ConfigOutputAttribute特性指定的枚举
|
||||
/// </summary>
|
||||
[ConfigOutputResource("")]
|
||||
int ResultOutput { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 指定该配置在获取输出时调用哪个方法
|
||||
///// </summary>
|
||||
//string OutputMethodName { get; set; }
|
||||
}
|
||||
|
||||
public interface IProcessID
|
||||
{
|
||||
/// <summary>
|
||||
/// 该配置对应的工序编号
|
||||
/// 考虑到多工序可能对应到同样的配置,工序编号不做固定赋值,在设备运作时随用随赋值
|
||||
/// </summary>
|
||||
string ProcessId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 工序名称
|
||||
/// </summary>
|
||||
string ProcessName { get; set; }
|
||||
}
|
||||
}
|
95
src/BRS.Common.Model/Interface/IProcess.cs
Normal file
95
src/BRS.Common.Model/Interface/IProcess.cs
Normal file
@ -0,0 +1,95 @@
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Reflection;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IProcess : ILogger, IExceptionHandler
|
||||
{
|
||||
#region 属性
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程配置
|
||||
/// </summary>
|
||||
IProcessConfig IConfig { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 带有[ProcessMethod]属性的所有方法集合,供设置界面选择使用
|
||||
/// </summary>
|
||||
List<ProcessMethodAttribute> ProcessMethodCollection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 调用方法的字典集合,键:方法名称字符串,值:方法对象
|
||||
/// Key:MethodCode,Value:MethodInfo
|
||||
/// </summary>
|
||||
Dictionary<string, MethodInfo> ProcessMethodDict { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程使用的硬件设备集合
|
||||
/// </summary>
|
||||
List<IDevice> DeviceCollection { get; set; }
|
||||
|
||||
|
||||
|
||||
string ProductionCode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程状态
|
||||
/// </summary>
|
||||
DeviceState ProcessState { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
/// <summary>
|
||||
/// 打开
|
||||
/// </summary>
|
||||
void Open(bool isServiceMode = false);
|
||||
|
||||
void Open();
|
||||
|
||||
/// <summary>
|
||||
/// 关闭
|
||||
/// </summary>
|
||||
void Close();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化Process
|
||||
/// </summary>
|
||||
void InitialProcess(string configPath);
|
||||
|
||||
void InitialProcess();
|
||||
|
||||
void InitialProcessMethods();
|
||||
#endregion
|
||||
|
||||
#region 事件
|
||||
///// <summary>
|
||||
///// 图像输出事件
|
||||
///// </summary>
|
||||
//event Action<string, Bitmap, string> OnBitmapOutput;
|
||||
|
||||
event Action<DeviceState> OnProcessStateChanged;
|
||||
event Action<RunState> OnProcessRunStateChanged;
|
||||
|
||||
event Action<IWarningSet> OnAlarmRaised;
|
||||
|
||||
event Action<DateTime, object, string> OnUpdateResult;
|
||||
event Action<DateTime, string> OnUpdateTriggerCount;
|
||||
event Action<object, float> OnUpdateCT;
|
||||
#endregion
|
||||
|
||||
#region 数据库操作
|
||||
void SaveProcessConfig(IProcessConfig config);
|
||||
void CreateNewConfig(IProcessConfig config, string newProductionCode, double pOutsideDiameter, double pHeight);
|
||||
#endregion
|
||||
}
|
||||
}
|
51
src/BRS.Common.Model/Interface/IProcessConfig.cs
Normal file
51
src/BRS.Common.Model/Interface/IProcessConfig.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IProcessConfig : IHalconToolPath, IMonitorSetCollection, INotifyPropertyChanged
|
||||
{
|
||||
#region Property
|
||||
string StationCode { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 是否采用离线图片
|
||||
///// </summary>
|
||||
//bool IsImageOffline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运行模式
|
||||
/// </summary>
|
||||
//RunMode RunMode { get; set; }
|
||||
|
||||
bool IsLogEnabled { get; set; }
|
||||
// string ImgPath { get; set; }
|
||||
string LogPath { get; set; }
|
||||
|
||||
LogLevel DefaultLogLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否输出CSV文件
|
||||
/// </summary>
|
||||
bool IsCSVOutputEnabled { get; set; }
|
||||
#endregion
|
||||
|
||||
|
||||
#region 设备配置
|
||||
List<IInitialConfig> CameraConfigCollection { get; set; }
|
||||
//
|
||||
List<IInitialConfig> PLCConfigCollection { get; set; }
|
||||
List<IInitialConfig> DeviceConfigs { get; set; }
|
||||
|
||||
|
||||
List<IInitialConfig> RobotConfigCollection { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Method
|
||||
List<IInitialConfig> GetAllDeviceInitialConfigs();
|
||||
#endregion
|
||||
}
|
||||
}
|
34
src/BRS.Common.Model/Interface/IProductData.cs
Normal file
34
src/BRS.Common.Model/Interface/IProductData.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using BRS.Common.Model;
|
||||
using BRS.Common.Model.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IProductData
|
||||
{
|
||||
string Id { get; set; }
|
||||
|
||||
List<DetectStationResult> ResultCollection { get; set; }
|
||||
|
||||
|
||||
|
||||
//event Action<IImageSet> OnImageSetTimeout;
|
||||
|
||||
///// <summary>
|
||||
///// 序列化操作的图像信息
|
||||
///// </summary>
|
||||
//string ImageData { get; set; }
|
||||
|
||||
//void SaveImage(string imageDir, Bitmap image = null, string imageName = "");
|
||||
}
|
||||
|
||||
}
|
48
src/BRS.Common.Model/Interface/IRemoteMessage.cs
Normal file
48
src/BRS.Common.Model/Interface/IRemoteMessage.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using BRS.Common.Model;
|
||||
using System;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IRemoteMessage
|
||||
{
|
||||
string Id { get; set; }
|
||||
|
||||
string MessageType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表示当前信息是反馈信息
|
||||
/// </summary>
|
||||
bool IsEcho { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表示当前信息是否需要即时反馈
|
||||
/// </summary>
|
||||
bool EnableEcho { get; set; }
|
||||
|
||||
ResponseMessage ResolveMessage(DateTime dt);
|
||||
}
|
||||
|
||||
//public interface IMessageResolver
|
||||
//{
|
||||
// static Func<IRemoteMessage, ResponseMessage> ResolveAction { get; set; }
|
||||
//}
|
||||
|
||||
public class RemoteMessageBase : IRemoteMessage
|
||||
{
|
||||
public virtual string Id { get; set; } = DateTime.Now.ToString("MMdd_HHmmssfff");
|
||||
public string MessageType { get; set; } = "";
|
||||
public bool IsEcho { get; set; } = false;
|
||||
public bool EnableEcho { get; set; } = false;
|
||||
|
||||
//public abstract ResponseMessage ResolveMessage();
|
||||
|
||||
public virtual ResponseMessage ResolveMessage(DateTime dt)
|
||||
{
|
||||
ResponseMessage msg = new ResponseMessage();
|
||||
msg.Result = -1;
|
||||
msg.Message = "消息解析器未实现";
|
||||
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
19
src/BRS.Common.Model/Interface/IRunCtrl.cs
Normal file
19
src/BRS.Common.Model/Interface/IRunCtrl.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IRunCtrl
|
||||
{
|
||||
IDevice Device { get; set; }
|
||||
|
||||
//IOperationConfig OpConfig { get; set; }
|
||||
|
||||
//void UploadOperationConfig(IOperationConfig opConfig);
|
||||
|
||||
//IOperationConfig GetOperationConfig();
|
||||
}
|
||||
|
||||
//public interface IEditCtrl
|
||||
//{
|
||||
// IRunCtrl RunCtrl { get; set; }
|
||||
// IOperationConfig OpConfig { get; set; }
|
||||
//}
|
||||
}
|
39
src/BRS.Common.Model/Interface/IShapeElement.cs
Normal file
39
src/BRS.Common.Model/Interface/IShapeElement.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using static BRS.Common.Model.Helper.EnumHelper;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
|
||||
public interface IShapeElement : INotifyPropertyChanged, ICloneable
|
||||
{
|
||||
string ID { get; set; }
|
||||
|
||||
int Index { get; set; }
|
||||
int GroupIndex { get; set; }
|
||||
|
||||
string Name { get; set; }
|
||||
|
||||
void OnMouseDown(PointF point);
|
||||
void OnMouseUp(PointF point);
|
||||
void OnMouseMove(PointF point);
|
||||
void OnMouseDoubleClick(PointF point);
|
||||
bool IsIntersect(RectangleF rect);
|
||||
|
||||
bool IsEnabled { get; set; }
|
||||
void Draw(Graphics g);
|
||||
|
||||
void Translate(float x, float y);
|
||||
|
||||
/// <summary>
|
||||
/// WPF中标识该对象是否已经加入渲染,需要显示
|
||||
/// </summary>
|
||||
bool IsShowing { get; set; }
|
||||
|
||||
void Initial();
|
||||
bool IsCreatedDone();
|
||||
|
||||
ElementState State { get; set; }
|
||||
}
|
||||
}
|
39
src/BRS.Common.Model/Interface/IWarningSetCollection.cs
Normal file
39
src/BRS.Common.Model/Interface/IWarningSetCollection.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BRS.Common.Interface
|
||||
{
|
||||
public interface IWarningSetCollection
|
||||
{
|
||||
List<IWarningSet> WarningSetCollection { get; set; }
|
||||
|
||||
//List<IWarningSet> GetAllWarningSet();
|
||||
}
|
||||
|
||||
public interface IWarningSet
|
||||
{
|
||||
//string Id { get; set; }
|
||||
|
||||
//string Name { get; set; }
|
||||
|
||||
string DisplayText { get; }
|
||||
|
||||
bool TriggerValue { get; set; }
|
||||
|
||||
string WarningCode { get; set; }
|
||||
|
||||
string WarningDescription { get; set; }
|
||||
|
||||
int WarningLvl { get; set; }
|
||||
|
||||
bool CurrentStatus { get; set; }
|
||||
|
||||
string SourceDevice { get; set; }
|
||||
|
||||
DateTime TriggerTime { get; set; }
|
||||
|
||||
DateTime LastTriggerTime { get; set; }
|
||||
|
||||
bool GetWarningSet(string txt);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user