添加项目文件。

This commit is contained in:
17860779768
2023-02-23 14:52:43 +08:00
parent 1db01eda58
commit 157613603c
508 changed files with 94132 additions and 0 deletions

View 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>

View 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
}
}

View 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;
}
}
}
}

View 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; }
}
}

View 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; }
}
}

View 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();
}
}
}

View File

@ -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()}";
}
}
}

View 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;
}
}

View 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;
});
}
}
}

View File

@ -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>

View File

@ -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);
}
}
}

View 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;
}
}

View 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;
}
}
}

View 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>

View 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,
}
}

View 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
}

View 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();
}
}

View 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
}
}

View 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);
}
}
}

View 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);
// }
//}
}

View 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
}
}

View 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
}

View 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);
// }
//}
}

View 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,
}
}

View 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
{
}
}

View 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);
}
}
}
}

View 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;
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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("检测信息显示位置。左上角为11向右向下为正方向")]
[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);
}
}
}

View 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
}

View 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 "";
}
}
}
}

View 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}";
}
}
}

View 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);
}
}

View 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")]

View 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;
}
}
}
}

View 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>

View 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>

View 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>

View 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;
}
}
}

View 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>

View 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
}
}

View 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;
// }
//}
}
}

View 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; }
}
}

View 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; }
}
}

View 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();
}
}
}

View 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
{
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace BRS.Common.Interface
{
public interface IExceptionHandler
{
Action<DateTime, Exception> OnExceptionOccured { get; set; }
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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>();
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}

View 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;
}
}
}
}
}

View 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>

View 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;
}
}

View 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;
}
}
}

View 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>

View 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();
//}
}
}

View 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>
/// 用来修饰对外开放的调用方法的特性
/// 调用方法参数顺序IOperationConfigInvokeDeviceSourceDevice
/// </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;
}
}
}

View 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;
}
}
}

View 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;
}
}

View 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;
}
}
}

View 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,
//}
}
}

View 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;
}
}
}

View 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;
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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}";
}
}
}

View 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对所定义的地址 用属性进行定义 以方便在类外进行访问及了解所对应地址的含义。
* 4GetAddressValueLength函数中 对使用说明的"第一步"分组 的元素个数进行指定。
* 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
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}

View 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));
}
}
}

View 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);
}
}
}

View 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
}

View 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;
}
}
}

View 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);
}
}
}

View File

@ -0,0 +1,9 @@
namespace BRS.Common.Interface
{
public interface ICSVOutput
{
string GetCSVHead();
string GetCSVData();
}
}

View 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();
}
}

View 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; }
}
}

View 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; }
}
}

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace BRS.Common.Interface
{
public interface IHalconToolPath
{
List<string> GetHalconToolPathList();
}
}

View 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; }
}
}

View 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);
//}
}
}
}

View 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; }
}
}

View 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);
}
}

View 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);
}
}

View 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; }
}
}

View 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; }
}
}

View 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; }
}
}

View 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; }
}
}

View 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>
/// 调用方法的字典集合,键:方法名称字符串,值:方法对象
/// KeyMethodCodeValueMethodInfo
/// </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
}
}

View 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
}
}

View 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 = "");
}
}

View 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;
}
}
}

View 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; }
//}
}

View 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; }
}
}

View 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