添加项目文件。
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
using PLCCommunication;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC接口
|
||||
/// </summary>
|
||||
public interface IPLC
|
||||
{
|
||||
/// <summary>
|
||||
/// 链接
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
bool Connect(ref string msg);
|
||||
/// <summary>
|
||||
/// 断开
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool Disconnect();
|
||||
|
||||
#region 读取
|
||||
/// <summary>
|
||||
/// 读取单个Bool
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
bool ReadBool(string address);
|
||||
/// <summary>
|
||||
/// 读取单个Int16整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
short ReadInt16(string address);
|
||||
/// <summary>
|
||||
/// 异步读取单个Int16整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
Task<JYResult<short>> ReadInt16Async(string address);
|
||||
/// <summary>
|
||||
/// 读取Int16数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
short[] ReadArrInt16(string address, ushort length);
|
||||
/// <summary>
|
||||
/// 异步读取Int16数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
Task<JYResult<short[]>> ReadArrInt16Async(string address, ushort length);
|
||||
/// <summary>
|
||||
/// 读取单个32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
int ReadInt32(string address);
|
||||
/// <summary>
|
||||
/// 异步读取单个32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
Task<JYResult<int>> ReadInt32Async(string address);
|
||||
/// <summary>
|
||||
/// 读取浮点型数据
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
float ReadFloat(string address);
|
||||
/// <summary>
|
||||
/// 异步读取float数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
Task<JYResult<float[]>> ReadArrFloatAsync(string address, ushort length);
|
||||
|
||||
/// <summary>
|
||||
/// 泛型读取
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
T ReadValue<T>(string address, DataType type, ushort length = 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 写入
|
||||
bool WriteBool(string address, bool value);
|
||||
bool WriteInt16(string address, short value);
|
||||
bool WriteInt32(string address, int value);
|
||||
bool WriteFloat(string address, float value);
|
||||
JYResult WriteValue(string address, object value, PLC.DataType type);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using PLCCommunication;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC基类
|
||||
/// </summary>
|
||||
public abstract class PlcReadWriteBase : IPLC
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的PLC对象
|
||||
/// </summary>
|
||||
/// <param name="pid"></param>
|
||||
/// <param name="pname">plc名</param>
|
||||
/// <param name="iep">PLC的IP和端口</param>
|
||||
/// <param name="timeout">PLC的通讯超时时间</param>
|
||||
public PlcReadWriteBase(int pid, string pname, IPEndPoint iep, int timeout = 10)
|
||||
{
|
||||
this.zPlcID = pid;
|
||||
this.zName = pname;
|
||||
this.IP = iep.Address.ToString();
|
||||
this.Port = iep.Port;
|
||||
this.Timeout = timeout;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string zName;// 允许继承类以后可以更改名称
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected int zPlcID;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Name { get { return zName; } }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int PlcID { get { return zPlcID; } }
|
||||
/// <summary>
|
||||
/// Ip地址
|
||||
/// </summary>
|
||||
public string IP { get; private set; }
|
||||
/// <summary>
|
||||
/// 端口号
|
||||
/// </summary>
|
||||
public int Port { get; private set; }
|
||||
/// <summary>
|
||||
/// 是否链接成功
|
||||
/// </summary>
|
||||
public bool IsConnected { get; set; }
|
||||
/// <summary>
|
||||
/// PLC 的通讯超时时间
|
||||
/// </summary>
|
||||
public int Timeout { get; private set; }
|
||||
/// <summary>
|
||||
/// 链接PLC
|
||||
/// </summary>
|
||||
public abstract bool Connect(ref string msg);
|
||||
/// <summary>
|
||||
/// 断开PLC
|
||||
/// </summary>
|
||||
public abstract bool Disconnect();
|
||||
/// <summary>
|
||||
/// 读取Plc内部boo变量
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool ReadBool(string address);
|
||||
/// <summary>
|
||||
/// 读取单个Int16整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public abstract short ReadInt16(string address);
|
||||
/// <summary>
|
||||
/// 异步读取单个Int16整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Task<JYResult<short>> ReadInt16Async(string address);
|
||||
/// <summary>
|
||||
/// 读取Int16数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public abstract short[] ReadArrInt16(string address, ushort length);
|
||||
/// <summary>
|
||||
/// 异步读取Int16数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Task<JYResult<short[]>> ReadArrInt16Async(string address, ushort length);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public abstract int ReadInt32(string address);
|
||||
/// <summary>
|
||||
/// 异步读取整数32位
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Task<JYResult<int>> ReadInt32Async(string address);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public abstract float ReadFloat(string address);
|
||||
/// <summary>
|
||||
/// 读取float数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public abstract float[] ReadArrFloat(string address, ushort length);
|
||||
/// <summary>
|
||||
/// 异步读取float数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Task<JYResult<float[]>> ReadArrFloatAsync(string address, ushort length);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public abstract T ReadValue<T>(string address, DataType type, ushort length = 0);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
public abstract bool WriteBool(string address, bool value);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool WriteInt16(string address, short value);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool WriteInt32(string address, int value);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool WriteFloat(string address, float value);
|
||||
/// <summary>
|
||||
/// 泛型写入数据
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public abstract JYResult WriteValue(string address, object value, PLC.DataType type = PLC.DataType.Short);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// 泛型定长数据队列
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class DataQueue<T>
|
||||
{
|
||||
public DataQueue(int length)
|
||||
{
|
||||
dataQueue = new Queue<T>(length);
|
||||
this.length = length;
|
||||
queueLocker = new object();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 队列长度
|
||||
/// </summary>
|
||||
private int length;
|
||||
/// <summary>
|
||||
/// 泛型队列
|
||||
/// </summary>
|
||||
private Queue<T> dataQueue;
|
||||
private readonly object queueLocker;
|
||||
|
||||
/// <summary>
|
||||
/// 向列尾插入元素
|
||||
/// 并移去列首超出数量的元素
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
lock (queueLocker)
|
||||
{
|
||||
dataQueue.Enqueue(value);
|
||||
if (dataQueue.Count > length)
|
||||
dataQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否整个队列的数据都相同、
|
||||
/// </summary>
|
||||
public bool IsSame
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (queueLocker)
|
||||
{
|
||||
if (dataQueue.Count < length)
|
||||
return false;
|
||||
|
||||
return dataQueue.Distinct().Count() == 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{486AECD0-C2BF-43C5-B7D7-88E565ADE4B7}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>PLC</RootNamespace>
|
||||
<AssemblyName>PLC</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\PLC.xml</DocumentationFile>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\PLC.xml</DocumentationFile>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PLCCommunication, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DataQueue.cs" />
|
||||
<Compile Include="Base\IPLC.cs" />
|
||||
<Compile Include="PLCAlarm\AlarmManager.cs" />
|
||||
<Compile Include="PlcLibrary\OmronCipNet.cs" />
|
||||
<Compile Include="PlcLibrary\OmronFinsTCP.cs" />
|
||||
<Compile Include="PLCAlarm\AlarmFileData.cs" />
|
||||
<Compile Include="PLCAlarm\PLCAlarmReader.cs" />
|
||||
<Compile Include="PLCAlarm\RecordAlarmData.cs" />
|
||||
<Compile Include="PLCAlarm\RecordType.cs" />
|
||||
<Compile Include="PLCData.cs" />
|
||||
<Compile Include="PLCDataTool.cs" />
|
||||
<Compile Include="PlcLibrary\PLCFactory.cs" />
|
||||
<Compile Include="Base\PlcReadWriteBase.cs" />
|
||||
<Compile Include="PlcLibrary\PLCType.cs" />
|
||||
<Compile Include="PlcLibrary\SiemensS7.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\JinYuan.Helper\JinYuan.Helper.csproj">
|
||||
<Project>{258D0AB7-2B4F-4D8F-A3CD-7A8CB4A85360}</Project>
|
||||
<Name>JinYuan.Helper</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Lib\PLCCommunication.dll" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC.PLCAlarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 从文件读取的PLC报警信息
|
||||
/// </summary>
|
||||
public class AlarmFileData
|
||||
{
|
||||
/// <summary>
|
||||
/// alarmData有5个元素,分别对应字,位,报警触发值,报警代码,报警信息
|
||||
/// </summary>
|
||||
/// <param name="alarmData"></param>
|
||||
public AlarmFileData(string[] alarmData)
|
||||
{
|
||||
Word = int.Parse(alarmData[0]);
|
||||
Bit = int.Parse(alarmData[1]);
|
||||
AlarmTriger = alarmData[2] == "1";
|
||||
AlarmCode = alarmData[3];
|
||||
AlarmInfo = alarmData[4];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报警字地址
|
||||
/// </summary>
|
||||
public int Word { get; set; }
|
||||
/// <summary>
|
||||
/// 报警位地址
|
||||
/// </summary>
|
||||
public int Bit { get; set; }
|
||||
/// <summary>
|
||||
/// 报警触发值
|
||||
/// (为true的话就是当读取值是true的时候触发这个报警)
|
||||
/// </summary>
|
||||
public bool AlarmTriger { get; set; }
|
||||
/// <summary>
|
||||
/// 要上传到mes的报警代码
|
||||
/// </summary>
|
||||
public string AlarmCode { get; set; }
|
||||
/// <summary>
|
||||
/// 报警说明
|
||||
/// </summary>
|
||||
public string AlarmInfo { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PLC.PLCAlarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警信息管理器
|
||||
/// </summary>
|
||||
public class AlarmManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, AlarmEntry> activeAlarms = new ConcurrentDictionary<string, AlarmEntry>();
|
||||
|
||||
/// <summary>
|
||||
/// 添加报警
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
public void AddAlarm(RecordAlarmDataArgs e)
|
||||
{
|
||||
var alarmInfo = new AlarmEntry
|
||||
{
|
||||
AlarmCode = e.AlarmCode,
|
||||
AlarmInfo = e.AlarmInfo,
|
||||
AlarmDate = e.AlarmDate,
|
||||
StartTime = e.StartTime
|
||||
};
|
||||
|
||||
activeAlarms.TryAdd(e.AlarmCode, alarmInfo);
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除报警
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
public void RemoveAlarm(RecordAlarmDataArgs e)
|
||||
{
|
||||
activeAlarms.TryRemove(e.AlarmCode, out _);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取报警文本
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetFormattedAlarmText()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var alarm in activeAlarms.Values.OrderByDescending(a => a.StartTime))
|
||||
{
|
||||
sb.AppendLine($"报警: 代码 {alarm.AlarmCode}, 内容 {alarm.AlarmInfo}, 日期 {alarm.AlarmDate}, 开始时间 {alarm.StartTime:HH:mm:ss}");
|
||||
}
|
||||
return sb.ToString().TrimEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取报警JOSN
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetActiveAlarmsJson()
|
||||
{
|
||||
return JsonConvert.SerializeObject(activeAlarms.Values);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报警类
|
||||
/// </summary>
|
||||
public class AlarmEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警代码
|
||||
/// </summary>
|
||||
public string AlarmCode { get; set; }
|
||||
/// <summary>
|
||||
/// 报警信息
|
||||
/// </summary>
|
||||
public string AlarmInfo { get; set; }
|
||||
/// <summary>
|
||||
/// 报警时间
|
||||
/// </summary>
|
||||
public string AlarmDate { get; set; }
|
||||
/// <summary>
|
||||
/// 报警开始时间
|
||||
/// </summary>
|
||||
public DateTime StartTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
using JinYuan.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC.PLCAlarm
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC报警记录模块
|
||||
/// </summary>
|
||||
public class PLCAlarmReader
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警模板(从触摸屏导出的报警数据)
|
||||
/// </summary>
|
||||
private readonly List<AlarmFileData> alarmFileDataList;
|
||||
/// <summary>
|
||||
/// 报警记录路径(实际记录下来的实时报警)
|
||||
/// </summary>
|
||||
private readonly string alarmRecordPath;
|
||||
/// <summary>
|
||||
/// 是否忽略报警状态下的新增报警
|
||||
/// </summary>
|
||||
private readonly bool ignoreAlarm;
|
||||
/// <summary>
|
||||
/// 报警记录类型
|
||||
/// </summary>
|
||||
private readonly RecordType recordType;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个报警读取器
|
||||
/// </summary>
|
||||
/// <param name="AlarmFilePath">报警文件路径
|
||||
/// <para>
|
||||
/// 文件格式 .csv
|
||||
/// <para>字,位,触发数值,报警代码,报警内容</para>
|
||||
/// <para>40000,0,1,E001,急停报警(IO:A1_I0.05)</para>
|
||||
/// <para>40000,1,1,E002,上下料安全门报警(IO:A1_I0.06)</para>
|
||||
/// </para>
|
||||
/// </param>
|
||||
/// <param name="AlarmRecordPath">报警记录目录路径</param>
|
||||
/// <param name="recType">报警记录类型</param>
|
||||
/// <param name="ignore">是否忽略报警状态下的新增报警</param>
|
||||
public PLCAlarmReader(string AlarmFilePath, string AlarmRecordPath, RecordType recType = RecordType.RecordWhenStart, bool ignore = false)
|
||||
{
|
||||
alarmFileDataList = ReadAlarmFile(AlarmFilePath);
|
||||
alarmRecordPath = AlarmRecordPath;
|
||||
recordType = recType;
|
||||
ignoreAlarm = ignore;
|
||||
RecordAlarms = new List<RecordAlarmDataArgs>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增报警事件
|
||||
/// </summary>
|
||||
public event EventHandler<RecordAlarmDataArgs> PLCAlarm_New;
|
||||
/// <summary>
|
||||
/// 报警复位事件
|
||||
/// </summary>
|
||||
public event EventHandler<RecordAlarmDataArgs> PLCAlarm_Remove;
|
||||
/// <summary>
|
||||
/// 当前记录中的报警
|
||||
/// </summary>
|
||||
public List<RecordAlarmDataArgs> RecordAlarms { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 读取本地报警文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<AlarmFileData> ReadAlarmFile(string alarmFilePath)
|
||||
{
|
||||
List<AlarmFileData> fileAlarmList = new List<AlarmFileData>();
|
||||
try
|
||||
{
|
||||
if (!File.Exists(alarmFilePath))
|
||||
return null;
|
||||
using (StreamReader sr = new StreamReader(alarmFilePath, Encoding.Default))
|
||||
{
|
||||
if (!sr.EndOfStream)
|
||||
sr.ReadLine(); // 读掉第一行标题行
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string[] alarmData = sr.ReadLine().Split('\t');
|
||||
fileAlarmList.Add(new AlarmFileData(alarmData));
|
||||
}
|
||||
}
|
||||
return fileAlarmList;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.WriteError("读取本地报警信息配置文件出错:" + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 寻找报警代码
|
||||
/// </summary>
|
||||
/// <param name="word">字地址</param>
|
||||
/// <param name="bit">位地址</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <param name="alarmData">报警信息</param>
|
||||
/// <returns>是否找到</returns>
|
||||
private bool FindAlarm(int word, int bit, bool value, out AlarmFileData alarmData)
|
||||
{
|
||||
if (alarmFileDataList == null)
|
||||
{
|
||||
alarmData = null;
|
||||
return false;
|
||||
}
|
||||
foreach (var item in alarmFileDataList)
|
||||
{
|
||||
if (item.Word == word &&
|
||||
item.Bit == bit &&
|
||||
item.AlarmTriger == value)
|
||||
{
|
||||
alarmData = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
alarmData = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得当前报警列表
|
||||
/// </summary>
|
||||
/// <param name="startAddr">报警字开始地址</param>
|
||||
/// <param name="addrStep">报警地址递增步进(个别情况用)
|
||||
/// <para>比如按字读取基恩士MR地址时,字地址是40000,40100,40200这样增加的,此时就要把addrStep设成100</para>
|
||||
/// </param>
|
||||
/// <param name="length">报警字长度(有几个字)</param>
|
||||
/// <param name="readDatas">读到的数据</param>
|
||||
/// <param name="readPLCAlrms">返回的当前报警列表</param>
|
||||
/// <returns></returns>
|
||||
private bool GenerateAlarmList(int startAddr, int length, ushort[] readDatas, out List<AlarmFileData> readPLCAlrms, int addrStep = 1)
|
||||
{
|
||||
bool isAlarm = false;
|
||||
readPLCAlrms = new List<AlarmFileData>();
|
||||
for (int wi = 0; wi < length; wi++)
|
||||
{
|
||||
ushort word = readDatas[wi];
|
||||
if (word != 0)
|
||||
{
|
||||
isAlarm = true;
|
||||
bool[] bits = PLCDataTool.WordToBits(word);
|
||||
for (int bi = 0; bi < 16; bi++)
|
||||
{
|
||||
if (FindAlarm(startAddr + wi * addrStep, bi, bits[bi], out AlarmFileData alarmdata))
|
||||
{
|
||||
if (!readPLCAlrms.Exists((p) => p.AlarmCode == alarmdata.AlarmCode))
|
||||
readPLCAlrms.Add(alarmdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isAlarm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输入读取的数据,判断当前是否报警,保存报警记录
|
||||
/// </summary>
|
||||
/// <param name="startAddr">报警字开始地址</param>
|
||||
/// <param name="addrStep">报警地址递增步进(个别情况用)
|
||||
/// <para>比如按字读取基恩士MR地址时,字地址是40000,40100,40200这样增加的,此时就要把addrStep设成100</para>
|
||||
/// </param>
|
||||
/// <param name="length">报警字长度(有几个字)</param>
|
||||
/// <param name="readDatas">读到的数据</param>
|
||||
/// <returns></returns>
|
||||
public bool IsPLCAlarm(int startAddr, int length, ushort[] readDatas, int addrStep = 1)
|
||||
{
|
||||
if (GenerateAlarmList(startAddr, length, readDatas, out List<AlarmFileData> readPLCAlrms, addrStep))
|
||||
{
|
||||
// 新增
|
||||
if (!ignoreAlarm || RecordAlarms.Count <= 0) //当不忽略报警状态下新增报警,或者当前是无报警状态的话,就记录
|
||||
{
|
||||
foreach (var alrmItem in readPLCAlrms)
|
||||
{
|
||||
if (RecordAlarms.Exists(p => p.AlarmCode == alrmItem.AlarmCode))
|
||||
continue;
|
||||
// 记录新增报警
|
||||
var recordData = new RecordAlarmDataArgs()
|
||||
{
|
||||
AlarmCode = alrmItem.AlarmCode,
|
||||
AlarmInfo = alrmItem.AlarmInfo,
|
||||
AlarmDate = DateTime.Now.ToString("yyyy/MM/dd"),
|
||||
StartTime = DateTime.Now
|
||||
};
|
||||
RecordAlarms.Add(recordData);
|
||||
SaveAlarmRecordWhenStart(recordData);
|
||||
OnAlarm_New(recordData);
|
||||
}
|
||||
}
|
||||
// 复位
|
||||
for (int i = RecordAlarms.Count - 1; i >= 0; i--)
|
||||
{
|
||||
// 遍历记录中的报警,如果有当前报警中不包含的报警项,说明报警已复位
|
||||
if (!readPLCAlrms.Exists(p => p.AlarmCode == RecordAlarms[i].AlarmCode))
|
||||
{
|
||||
SaveAlarmRecordWhenFinish(RecordAlarms[i], DateTime.Now);
|
||||
OnAlarm_Remove(RecordAlarms[i]);
|
||||
RecordAlarms.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 全都复位
|
||||
for (int i = RecordAlarms.Count - 1; i >= 0; i--)
|
||||
{
|
||||
SaveAlarmRecordWhenFinish(RecordAlarms[i], DateTime.Now);
|
||||
OnAlarm_Remove(RecordAlarms[i]);
|
||||
RecordAlarms.RemoveAt(i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发新增报警事件
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void OnAlarm_New(RecordAlarmDataArgs args)
|
||||
{
|
||||
// 以线程安全的方式引发事件
|
||||
var temp = PLCAlarm_New;
|
||||
temp?.Invoke(this, args);
|
||||
}
|
||||
/// <summary>
|
||||
/// 触发报警复位事件
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private void OnAlarm_Remove(RecordAlarmDataArgs args)
|
||||
{
|
||||
// 以线程安全的方式引发事件
|
||||
var temp = PLCAlarm_Remove;
|
||||
temp?.Invoke(this, args);
|
||||
}
|
||||
|
||||
|
||||
#region 保存报警记录
|
||||
/// <summary>
|
||||
/// 当报警消除的时候记录已消除的报警
|
||||
/// </summary>
|
||||
/// <param name="alrmData">报警数据</param>
|
||||
/// <param name="endTime">结束时间</param>
|
||||
private void SaveAlarmRecordWhenFinish(RecordAlarmDataArgs alrmData, DateTime endTime)
|
||||
{
|
||||
if (recordType != RecordType.RecordWhenFinish)
|
||||
return;
|
||||
|
||||
string start = alrmData.StartTime.ToString("HH:mm:ss");
|
||||
string end = endTime.ToString("HH:mm:ss");
|
||||
string totaltime = (endTime - alrmData.StartTime).TotalMinutes.ToString("f2");
|
||||
|
||||
if (!Directory.Exists(alarmRecordPath))
|
||||
{
|
||||
Directory.CreateDirectory(alarmRecordPath);
|
||||
}
|
||||
try
|
||||
{
|
||||
string filePath = Path.Combine(alarmRecordPath, DateTime.Now.ToString("yyyy-MM-dd") + ".csv");
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(filePath))
|
||||
{
|
||||
sw.WriteLine("报警信息,报警代码,统计日期,开始时间,结束时间,消耗时间(min)");
|
||||
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start + "," + end + "," + totaltime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(filePath, true))
|
||||
{
|
||||
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start + "," + end + "," + totaltime);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.WriteError(ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当报警触发的时候记录报警
|
||||
/// </summary>
|
||||
/// <param name="alrmData">报警数据</param>
|
||||
private void SaveAlarmRecordWhenStart(RecordAlarmDataArgs alrmData)
|
||||
{
|
||||
if (recordType != RecordType.RecordWhenStart)
|
||||
return;
|
||||
|
||||
string start = alrmData.StartTime.ToString("HH:mm:ss");
|
||||
|
||||
if (!Directory.Exists(alarmRecordPath))
|
||||
{
|
||||
Directory.CreateDirectory(alarmRecordPath);
|
||||
}
|
||||
try
|
||||
{
|
||||
string filePath = Path.Combine(alarmRecordPath, DateTime.Now.ToString("yyyy-MM-dd") + ".csv");
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(filePath))
|
||||
{
|
||||
sw.WriteLine("报警信息,报警代码,统计日期,开始时间");
|
||||
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(filePath, true))
|
||||
{
|
||||
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.WriteError(ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC.PLCAlarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警记录数据(同时作为报警事件的事件参数)
|
||||
/// </summary>
|
||||
public class RecordAlarmDataArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警信息
|
||||
/// </summary>
|
||||
public string AlarmInfo { get; set; }
|
||||
/// <summary>
|
||||
/// 报警代码
|
||||
/// </summary>
|
||||
public string AlarmCode { get; set; }
|
||||
/// <summary>
|
||||
/// 报警日期
|
||||
/// </summary>
|
||||
public string AlarmDate { get; set; }
|
||||
/// <summary>
|
||||
/// 报警开始时间
|
||||
/// </summary>
|
||||
public DateTime StartTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC.PLCAlarm
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警文件记录选项
|
||||
/// </summary>
|
||||
public enum RecordType
|
||||
{
|
||||
/// <summary>
|
||||
/// 不记录
|
||||
/// </summary>
|
||||
NoRecord,
|
||||
/// <summary>
|
||||
/// 报警触发的时候记录
|
||||
/// </summary>
|
||||
RecordWhenStart,
|
||||
/// <summary>
|
||||
/// 报警复位的时候记录
|
||||
/// </summary>
|
||||
RecordWhenFinish
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T">读取的值类型</typeparam>
|
||||
public struct PLCData<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 字地址
|
||||
/// </summary>
|
||||
public int WordAddr { get; set; }
|
||||
/// <summary>
|
||||
/// 位地址
|
||||
/// </summary>
|
||||
public int BitAddr { get; set; }
|
||||
/// <summary>
|
||||
/// 功能
|
||||
/// </summary>
|
||||
public string Function { get; set; }
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Info { get; set; }
|
||||
/// <summary>
|
||||
/// 数据类型
|
||||
/// </summary>
|
||||
public DataType DataType { get; set; }
|
||||
/// <summary>
|
||||
/// 高低位类型
|
||||
/// </summary>
|
||||
public HightLowType HightLowType { get; set; }
|
||||
/// <summary>
|
||||
/// 读取的值
|
||||
/// </summary>
|
||||
public T Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取数据类型
|
||||
/// </summary>
|
||||
//public enum DataType
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 位
|
||||
// /// </summary>
|
||||
// Bit = 0,
|
||||
// /// <summary>
|
||||
// /// 短整型 16位
|
||||
// /// </summary>
|
||||
// Short,
|
||||
// /// <summary>
|
||||
// /// 整型 32位
|
||||
// /// </summary>
|
||||
// Int,
|
||||
// /// <summary>
|
||||
// /// 浮点 32位
|
||||
// /// </summary>
|
||||
// Float
|
||||
//}
|
||||
|
||||
public enum DataType
|
||||
{
|
||||
[Description("Bool")]
|
||||
Bool,
|
||||
[Description("Short")]
|
||||
Short,
|
||||
[Description("Int")]
|
||||
Int,
|
||||
[Description("Float")]
|
||||
Float,
|
||||
[Description("Double")]
|
||||
Double,
|
||||
[Description("String")]
|
||||
String,
|
||||
[Description("ArrByte")]
|
||||
ArrByte,
|
||||
[Description("ArrFloat")]
|
||||
ArrFloat,
|
||||
[Description("ArrShort")]
|
||||
ArrShort,
|
||||
[Description("ArrUshort")]
|
||||
ArrUshort,
|
||||
[Description("ArrInt")]
|
||||
ArrInt,
|
||||
[Description("ArrUint")]
|
||||
ArrUint,
|
||||
|
||||
|
||||
}
|
||||
|
||||
public enum HightLowType
|
||||
{
|
||||
_12,
|
||||
_21,
|
||||
_4321
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
|
||||
using JinYuan.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class PLCDataTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 将字节数组转成16进制字符串
|
||||
/// </summary>
|
||||
/// <param name="hex"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <returns></returns>
|
||||
public static string Byte2HexString(byte[] hex, int len)
|
||||
{
|
||||
string returnstr = "";
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
returnstr += hex[i].ToString("X2");
|
||||
}
|
||||
return returnstr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把字符串截取成每个元素2个字符的字符串数组
|
||||
/// </summary>
|
||||
/// <param name="src"></param>
|
||||
/// <param name="notDataCounts">前置非数据字节数,omron为30,Mitsubishi为11</param>
|
||||
/// <returns></returns>
|
||||
public static string[] Str2StrArray(string src, int notDataCounts)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res;
|
||||
|
||||
src = src.Substring(2 * notDataCounts);
|
||||
|
||||
res = new string[src.Length / 2];
|
||||
for (int i = 0; i < src.Length / 2; i++)
|
||||
{
|
||||
res[i] = src.Substring(i * 2, 2);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
LogHelper.Instance.WriteError(exp.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将条码转换成UInt16数组
|
||||
/// <para>没两个字符对应一个UInt16</para>
|
||||
/// </summary>
|
||||
/// <param name="barcode"></param>
|
||||
/// <returns></returns>
|
||||
public static int[] BarcodeTransfer(string barcode)
|
||||
{
|
||||
|
||||
byte[] bt = Encoding.ASCII.GetBytes(barcode);
|
||||
if (bt.Length % 2 != 0)
|
||||
{
|
||||
bt = bt.Concat(new byte[] { 0 }).ToArray();
|
||||
}
|
||||
int[] result = new int[bt.Length / 2];
|
||||
for (int i = 0; i < bt.Length / 2; i++)
|
||||
{
|
||||
result[i] = Convert.ToUInt16(bt[2 * i].ToString("X2") + bt[2 * i + 1].ToString("X2"), 16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 位转字
|
||||
/// 输入一个长度16的bool数组,返回一个Int16形式的字
|
||||
/// <para>高位在左,低位在右</para>
|
||||
/// </summary>
|
||||
/// <param name="bits"></param>
|
||||
/// <returns>Word</returns>
|
||||
public static ushort BitsToWord(bool[] bits)
|
||||
{
|
||||
ushort result = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (bits[i])
|
||||
result |= (ushort)(1 << i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字转位
|
||||
/// 输入一个Int16形式的字,返回一个长度16的bool数组
|
||||
/// </summary>
|
||||
/// <param name="word"></param>
|
||||
/// <returns>Bits</returns>
|
||||
public static bool[] WordToBits(ushort word)
|
||||
{
|
||||
bool[] result = new bool[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
result[i] = ((word >> i) & 1) == 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 位转字节
|
||||
/// </summary>
|
||||
/// <param name="bits"></param>
|
||||
/// <returns></returns>
|
||||
public static byte BitsToByte(bool[] bits)
|
||||
{
|
||||
byte result = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (bits[i])
|
||||
result |= (byte)(1 << i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字节转位
|
||||
/// </summary>
|
||||
/// <param name="bt"></param>
|
||||
/// <returns></returns>
|
||||
public static bool[] ByteToBits(byte bt)
|
||||
{
|
||||
bool[] result = new bool[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
result[i] = ((bt >> i) & 1) == 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把两个uint16的数据合并成一个float
|
||||
/// </summary>
|
||||
/// <param name="High"></param>
|
||||
/// <param name="Low"></param>
|
||||
/// <returns></returns>
|
||||
public static double TwoUInt16ToFloat(ushort High, ushort Low)
|
||||
{
|
||||
int int_32 = (High << 16) | Low;
|
||||
|
||||
return BitConverter.ToSingle(BitConverter.GetBytes(int_32), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把float分隔成两个int16
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns>低位在前高位在后</returns>
|
||||
public static ushort[] FloatToTwoUInt16(float value)
|
||||
{
|
||||
byte[] bs = BitConverter.GetBytes(value);
|
||||
|
||||
ushort low = BitConverter.ToUInt16(bs, 0);
|
||||
ushort high = BitConverter.ToUInt16(bs, 2);
|
||||
|
||||
return new ushort[2] { low, high };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把int分隔成两个int16
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns>低位在前高位在后</returns>
|
||||
public static ushort[] Int32ToTwoUInt16(int value)
|
||||
{
|
||||
byte[] bs = BitConverter.GetBytes(value);
|
||||
|
||||
ushort low = BitConverter.ToUInt16(bs, 0);
|
||||
ushort high = BitConverter.ToUInt16(bs, 2);
|
||||
|
||||
return new ushort[2] { low, high };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把两个Int16的数据合并成一个Int32
|
||||
/// </summary>
|
||||
/// <param name="High"></param>
|
||||
/// <param name="Low"></param>
|
||||
/// <returns></returns>
|
||||
public static int TwoInt16ToInt32(short High, short Low)
|
||||
{
|
||||
return ((ushort)High << 16) | (ushort)Low;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
|
||||
using PLCCommunication;
|
||||
using PLCCommunication.PLCType.Omron;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Export("OmronCipNet", typeof(PlcReadWriteBase))]
|
||||
public class OmronCipNet : PlcReadWriteBase
|
||||
{
|
||||
private PLCCommunication.PLCType.Omron.OmronCipNet omronCipNet = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="pid"></param>
|
||||
/// <param name="pname"></param>
|
||||
/// <param name="iep"></param>
|
||||
/// <param name="timeout"></param>
|
||||
public OmronCipNet(int pid, string pname, IPEndPoint iep, int timeout = 10) :
|
||||
base(pid, pname, iep, timeout)
|
||||
{
|
||||
omronCipNet = new PLCCommunication.PLCType.Omron.OmronCipNet();
|
||||
omronCipNet.IpAddress = iep.Address.ToString();
|
||||
omronCipNet.Port = iep.Port;
|
||||
omronCipNet.Slot = (byte)0;
|
||||
omronCipNet.SocketKeepAliveTime = 60000;
|
||||
omronCipNet.ConnectTimeOut = 1000;
|
||||
omronCipNet.ReceiveTimeOut = 1000;
|
||||
|
||||
IsConnected = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动与PLC链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool Connect(ref string msg)
|
||||
{
|
||||
bool res = false;
|
||||
try
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
omronCipNet.ConnectClose();
|
||||
JYResult connect = omronCipNet.ConnectServer();
|
||||
if (connect.IsSuccess)
|
||||
{
|
||||
IsConnected = connect.IsSuccess;
|
||||
|
||||
msg = StringResources.Language.ConnectedSuccess;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.Message;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开与PLC链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool Disconnect()
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
JYResult connect = omronCipNet.ConnectClose();
|
||||
IsConnected = false;
|
||||
return connect.IsSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取BOOl变量
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override bool ReadBool(string address)
|
||||
{
|
||||
JYResult<bool[]> result = omronCipNet.ReadBool(address, 1);
|
||||
if (result.IsSuccess)
|
||||
return result.Content[0];
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取16位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override short ReadInt16(string address)
|
||||
{
|
||||
|
||||
short result = 0;
|
||||
try
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
result = omronCipNet.ReadInt16(address).Content;
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override Task<JYResult<short>> ReadInt16Async(string address)
|
||||
{
|
||||
JYResult<short> result = null;
|
||||
try
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
result = omronCipNet.ReadInt16Async(address).Result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override int ReadInt32(string address)
|
||||
{
|
||||
int result = 0;
|
||||
try
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
result = omronCipNet.ReadInt32(address).Content;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override Task<JYResult<int>> ReadInt32Async(string address)
|
||||
{
|
||||
JYResult<int> result = null;
|
||||
try
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
result = omronCipNet.ReadInt32Async(address).Result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取Float单精度小数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override float ReadFloat(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
JYResult<float> result = omronCipNet.ReadFloat(address);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return result.Content;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取浮点数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override float[] ReadArrFloat(string address, ushort length)
|
||||
{
|
||||
float[] floats = new float[length];
|
||||
try
|
||||
{
|
||||
JYResult<float[]> result = omronCipNet.ReadFloat(address, length);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
floats = result.Content;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取PLC数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override T ReadValue<T>(string address, DataType type, ushort length = 0)
|
||||
{
|
||||
object obj = default(object);
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataType.Bool:
|
||||
obj = omronCipNet.ReadBool(address);
|
||||
break;
|
||||
case DataType.Short:
|
||||
obj = omronCipNet.ReadInt16(address);
|
||||
break;
|
||||
case DataType.Int:
|
||||
obj = omronCipNet.ReadInt32(address);
|
||||
break;
|
||||
case DataType.Float:
|
||||
obj = omronCipNet.ReadFloat(address);
|
||||
break;
|
||||
case DataType.Double:
|
||||
obj = omronCipNet.ReadDouble(address);
|
||||
break;
|
||||
case DataType.String:
|
||||
obj = omronCipNet.ReadString(address, length);
|
||||
break;
|
||||
case DataType.ArrByte:
|
||||
obj = omronCipNet.Read(address, length);
|
||||
break;
|
||||
case DataType.ArrFloat:
|
||||
obj = omronCipNet.ReadFloat(address, length);
|
||||
//obj = ReadArrFloat(address, length);
|
||||
break;
|
||||
case DataType.ArrShort:
|
||||
obj = omronCipNet.ReadInt16(address, length);
|
||||
break;
|
||||
case DataType.ArrUshort:
|
||||
obj = omronCipNet.ReadUInt16(address, length);
|
||||
break;
|
||||
case DataType.ArrInt:
|
||||
obj = omronCipNet.ReadUInt32(address, length);
|
||||
break;
|
||||
case DataType.ArrUint:
|
||||
obj = omronCipNet.ReadUInt32(address, length);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (T)obj;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool WriteBool(string address, bool value)
|
||||
{
|
||||
bool[] data = new bool[1] { value };
|
||||
JYResult result = omronCipNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入16位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
///
|
||||
public override bool WriteInt16(string address, short value)
|
||||
{
|
||||
JYResult result = omronCipNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
/// <summary>
|
||||
/// 写入32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool WriteInt32(string address, int value)
|
||||
{
|
||||
JYResult result = omronCipNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入浮点数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool WriteFloat(string address, float value)
|
||||
{
|
||||
JYResult result = omronCipNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写入PLC数据
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public override JYResult WriteValue(string address, object value, DataType type = DataType.Short)
|
||||
{
|
||||
JYResult result = new JYResult();
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataType.Bool:
|
||||
result = omronCipNet.Write(address, Convert.ToBoolean(value));
|
||||
break;
|
||||
case DataType.Short:
|
||||
result = omronCipNet.Write(address, Convert.ToInt16(value));
|
||||
break;
|
||||
case DataType.Int:
|
||||
result = omronCipNet.Write(address, Convert.ToInt32(value));
|
||||
break;
|
||||
case DataType.Float:
|
||||
result = omronCipNet.Write(address, Convert.ToSingle(value));
|
||||
break;
|
||||
case DataType.Double:
|
||||
result = omronCipNet.Write(address, Convert.ToDouble(value));
|
||||
break;
|
||||
case DataType.String:
|
||||
result = omronCipNet.Write(address, value.ToString());
|
||||
break;
|
||||
case DataType.ArrShort:
|
||||
result = omronCipNet.Write(address, value as short[]);
|
||||
//result = omronCipNet.Write(address, new short[] { 0, 1, 1,1 });
|
||||
break;
|
||||
case DataType.ArrByte:
|
||||
result = omronCipNet.Write(address, value as byte[]);
|
||||
break;
|
||||
case DataType.ArrFloat:
|
||||
result = omronCipNet.Write(address, value as float[]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.Message = ex.Message;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 读取16位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override short[] ReadArrInt16(string address, ushort length)
|
||||
{
|
||||
short[] floats = new short[length];
|
||||
try
|
||||
{
|
||||
JYResult<short[]> result = omronCipNet.ReadInt16(address, length);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
floats = result.Content;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
public override async Task<JYResult<short[]>> ReadArrInt16Async(string address, ushort length)
|
||||
{
|
||||
JYResult<short[]> result = new JYResult<short[]>();
|
||||
try
|
||||
{
|
||||
result = await omronCipNet.ReadInt16Async(address, length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.Message = ex.Message;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取浮点数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<JYResult<float[]>> ReadArrFloatAsync(string address, ushort length)
|
||||
{
|
||||
JYResult<float[]> result = new JYResult<float[]>();
|
||||
try
|
||||
{
|
||||
result = await omronCipNet.ReadFloatAsync(address, length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.Message = ex.Message;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using PLCCommunication;
|
||||
using PLCCommunication.PLCType.Omron;
|
||||
using PLCCommunication.Common;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Net;
|
||||
using PLCCommunication.Common.DataConvert;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// 欧姆龙FinsTCP通讯
|
||||
/// </summary>
|
||||
[Export("OmronFinsTCP", typeof(PlcReadWriteBase))]
|
||||
public class OmronFinsTCP : PlcReadWriteBase
|
||||
{
|
||||
private OmronFinsNet omronFinsNet = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="pid"></param>
|
||||
/// <param name="pname"></param>
|
||||
/// <param name="iep"></param>
|
||||
/// <param name="timeout"></param>
|
||||
public OmronFinsTCP(int pid, string pname, IPEndPoint iep, int timeout = 10) :
|
||||
base(pid, pname, iep, timeout)
|
||||
{
|
||||
omronFinsNet = new OmronFinsNet();
|
||||
omronFinsNet.IpAddress = iep.Address.ToString();
|
||||
omronFinsNet.Port = iep.Port;
|
||||
omronFinsNet.DA2 = 0x00;// PLC单元号,通常为0
|
||||
omronFinsNet.ReadSplits = 999; //读取字长度,最长999,不能超过1000
|
||||
omronFinsNet.ByteTransform.DataFormat = PLCCommunication.Common.DataFormat.CDAB;
|
||||
omronFinsNet.ByteTransform.IsStringReverseByteWord = true;
|
||||
omronFinsNet.ConnectTimeOut = 2000;
|
||||
omronFinsNet.ReceiveTimeOut = 2000;
|
||||
IsConnected = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动与PLC链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool Connect(ref string msg)
|
||||
{
|
||||
bool res = false;
|
||||
try
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
JYResult connect = omronFinsNet.ConnectServer();
|
||||
if (connect.IsSuccess)
|
||||
{
|
||||
IsConnected = connect.IsSuccess;
|
||||
byte num1 = this.omronFinsNet.SA1;
|
||||
byte num2 = this.omronFinsNet.DA1;
|
||||
msg = $"{num1},{num2}";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.Message;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开与PLC链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool Disconnect()
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
JYResult connect = omronFinsNet.ConnectClose();
|
||||
IsConnected = false;
|
||||
return connect.IsSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取BOOl变量
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override bool ReadBool(string address)
|
||||
{
|
||||
JYResult<bool[]> result = omronFinsNet.ReadBool(address, 1);
|
||||
if (result.IsSuccess)
|
||||
return result.Content[0];
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取16位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override short ReadInt16(string address)
|
||||
{
|
||||
JYResult<short> result = omronFinsNet.ReadInt16(address);
|
||||
if (result.IsSuccess)
|
||||
return result.Content;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override Task<JYResult<short>> ReadInt16Async(string address)
|
||||
{
|
||||
JYResult<short> result = null;
|
||||
try
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
result = omronFinsNet.ReadInt16Async(address).Result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取16位数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override short[] ReadArrInt16(string address, ushort length)
|
||||
{
|
||||
JYResult<byte[]> result = omronFinsNet.Read(address, length);
|
||||
if (result.IsSuccess)
|
||||
return ParseShortData(result.Content);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<JYResult<short[]>> ReadArrInt16Async(string address, ushort length)
|
||||
{
|
||||
JYResult<byte[]> result = await omronFinsNet.ReadAsync(address, length);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
short[] parsedData = ParseShortData(result.Content);
|
||||
return new JYResult<short[]> { Content = parsedData, IsSuccess = true };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new JYResult<short[]> { IsSuccess = false, Message = result.Message };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override int ReadInt32(string address)
|
||||
{
|
||||
JYResult<int> result = omronFinsNet.ReadInt32(address);
|
||||
if (result.IsSuccess)
|
||||
return result.Content;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取Float单精度小数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override float ReadFloat(string address)
|
||||
{
|
||||
JYResult<float> result = omronFinsNet.ReadFloat(address);
|
||||
if (result.IsSuccess)
|
||||
return result.Content;
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取Float数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override float[] ReadArrFloat(string address, ushort length = 0)
|
||||
{
|
||||
JYResult<byte[]> result = omronFinsNet.Read(address, length);
|
||||
if (result.IsSuccess)
|
||||
return ParseFloatData(result.Content);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取有符号16位数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private short[] ReadArrShort(string address, ushort length = 0)
|
||||
{
|
||||
JYResult<byte[]> result = omronFinsNet.Read(address, length);
|
||||
if (result.IsSuccess)
|
||||
return ParseShortData(result.Content);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 读取无符号16位数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private ushort[] ReadArrUshort(string address, ushort length = 0)
|
||||
{
|
||||
JYResult<byte[]> result = omronFinsNet.Read(address, length);
|
||||
if (result.IsSuccess)
|
||||
return ParseUshortData(result.Content);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private int[] ReadArrInt32(string address, ushort length = 0)
|
||||
{
|
||||
JYResult<byte[]> result = omronFinsNet.Read(address, length);
|
||||
if (result.IsSuccess)
|
||||
return ParseInt32Data(result.Content);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<JYResult<int>> ReadInt32Async(string address)
|
||||
{
|
||||
|
||||
JYResult<int> result = await omronFinsNet.ReadInt32Async(address);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
|
||||
return new JYResult<int> { Content = result.Content, IsSuccess = true };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new JYResult<int> { IsSuccess = false, Message = result.Message };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取浮点数组
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<JYResult<float[]>> ReadArrFloatAsync(string address, ushort length)
|
||||
{
|
||||
JYResult<byte[]> result = await omronFinsNet.ReadAsync(address,length);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
float[] floats = ParseFloatData(result.Content);
|
||||
return new JYResult<float[]> { Content = floats, IsSuccess = true };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new JYResult<float[]> { IsSuccess = false, Message = result.Message };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private short[] ParseShortData(byte[] content)
|
||||
{
|
||||
int count = content.Length / 2;
|
||||
return Enumerable.Range(0, count)
|
||||
.Select(i => (short)ShortLib.GetShortFromByteArray(content, i * 2))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private ushort[] ParseUshortData(byte[] content)
|
||||
{
|
||||
int count = content.Length / 2;
|
||||
return Enumerable.Range(0, count)
|
||||
.Select(i => (ushort)UShortLib.GetUShortFromByteArray(content, i * 2))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private int[] ParseInt32Data(byte[] content)
|
||||
{
|
||||
int count = content.Length / 2;
|
||||
return Enumerable.Range(0, count)
|
||||
.Select(i => (Int32)IntLib.GetIntFromByteArray(content, i * 4))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private float[] ParseFloatData(byte[] content)
|
||||
{
|
||||
int count = content.Length / 4;
|
||||
return Enumerable.Range(0, count)
|
||||
.Select(i => (float)FloatLib.GetFloatFromByteArray(content, i * 4))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取PLC数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public override T ReadValue<T>(string address, DataType type, ushort length = 0)
|
||||
{
|
||||
object obj = default(object);
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataType.Bool:
|
||||
obj = omronFinsNet.ReadBool(address);
|
||||
break;
|
||||
case DataType.Short:
|
||||
obj = omronFinsNet.ReadInt16(address);
|
||||
break;
|
||||
case DataType.Int:
|
||||
obj = omronFinsNet.ReadInt32(address);
|
||||
break;
|
||||
case DataType.Float:
|
||||
obj = omronFinsNet.ReadFloat(address);
|
||||
break;
|
||||
case DataType.Double:
|
||||
obj = omronFinsNet.ReadDouble(address);
|
||||
break;
|
||||
case DataType.String:
|
||||
obj = omronFinsNet.ReadString(address, length);
|
||||
break;
|
||||
case DataType.ArrByte:
|
||||
obj = omronFinsNet.Read(address, length);
|
||||
break;
|
||||
case DataType.ArrFloat:
|
||||
//obj = ReadArrFloat(address, length);
|
||||
obj = omronFinsNet.ReadFloat(address, length);
|
||||
break;
|
||||
case DataType.ArrShort:
|
||||
obj = omronFinsNet.ReadInt16(address, length);
|
||||
break;
|
||||
case DataType.ArrUshort:
|
||||
obj = omronFinsNet.ReadUInt16(address, length);
|
||||
break;
|
||||
case DataType.ArrInt:
|
||||
obj = omronFinsNet.ReadUInt32(address, length);
|
||||
break;
|
||||
case DataType.ArrUint:
|
||||
obj = omronFinsNet.ReadUInt32(address, length);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (T)obj;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool WriteBool(string address, bool value)
|
||||
{
|
||||
bool[] data = new bool[1] { value };
|
||||
JYResult result = omronFinsNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入16位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
///
|
||||
public override bool WriteInt16(string address, short value)
|
||||
{
|
||||
JYResult result = omronFinsNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
/// <summary>
|
||||
/// 写入32位整数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool WriteInt32(string address, int value)
|
||||
{
|
||||
JYResult result = omronFinsNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入浮点数
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool WriteFloat(string address, float value)
|
||||
{
|
||||
JYResult result = omronFinsNet.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写入PLC数据
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public override JYResult WriteValue(string address, object value, DataType type = DataType.Short)
|
||||
{
|
||||
JYResult result = new JYResult();
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataType.Bool:
|
||||
result = omronFinsNet.Write(address, Convert.ToBoolean(value));
|
||||
break;
|
||||
case DataType.Short:
|
||||
result = omronFinsNet.Write(address, Convert.ToInt16(value));
|
||||
break;
|
||||
case DataType.Int:
|
||||
result = omronFinsNet.Write(address, Convert.ToInt32(value));
|
||||
break;
|
||||
case DataType.Float:
|
||||
result = omronFinsNet.Write(address, Convert.ToSingle(value));
|
||||
break;
|
||||
case DataType.Double:
|
||||
result = omronFinsNet.Write(address, Convert.ToDouble(value));
|
||||
break;
|
||||
case DataType.String:
|
||||
result = omronFinsNet.Write(address, value.ToString());
|
||||
break;
|
||||
case DataType.ArrShort:
|
||||
result = omronFinsNet.Write(address, value as short[]);
|
||||
break;
|
||||
case DataType.ArrUshort:
|
||||
result = omronFinsNet.Write(address, value as ushort[]);
|
||||
break;
|
||||
case DataType.ArrByte:
|
||||
result = omronFinsNet.Write(address, value as byte[]);
|
||||
break;
|
||||
case DataType.ArrFloat:
|
||||
result = omronFinsNet.Write(address, value as float[]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.Message = ex.Message;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using PLCCommunication.PLCType.Siemens;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC工厂
|
||||
/// </summary>
|
||||
public class PLCFactory
|
||||
{
|
||||
private static Dictionary<PLCType, Type> plcTypes = new Dictionary<PLCType, Type>
|
||||
{
|
||||
{ PLCType.OmronFinsTCP, typeof(OmronFinsTCP) },
|
||||
{ PLCType.OmronCipNet, typeof(OmronCipNet) },
|
||||
{ PLCType.Siemens, typeof(SiemensS7) },
|
||||
|
||||
//{ PLCType.Mitsubishi, typeof(MitsubishiPLC) },
|
||||
// 添加其他 PLC 类型和对应的类...
|
||||
};
|
||||
|
||||
public static PlcReadWriteBase CreatePLC(PLCType type, int pid, string pname, IPEndPoint iep, int timeout = 10)
|
||||
{
|
||||
if (!plcTypes.TryGetValue(type, out Type plcType))
|
||||
{
|
||||
throw new ArgumentException($"不支持的 PLC 类型: {type}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (PlcReadWriteBase)Activator.CreateInstance(plcType, pid, pname, iep, timeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"创建 PLC 类型时出错 {type}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static PlcReadWriteBase CreatePLC(string typeName, int pid, string pname, IPEndPoint iep, int timeout = 10)
|
||||
{
|
||||
if (!Enum.TryParse(typeName, true, out PLCType type))
|
||||
{
|
||||
throw new ArgumentException($"PLC 类型名称无效: {typeName}");
|
||||
}
|
||||
|
||||
return CreatePLC(type, pid, pname, iep, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC类型
|
||||
/// </summary>
|
||||
public enum PLCType
|
||||
{
|
||||
/// <summary>
|
||||
/// 欧姆龙 Fins协议
|
||||
/// </summary>
|
||||
OmronFinsTCP,
|
||||
/// <summary>
|
||||
/// 欧姆龙 Fins协议
|
||||
/// </summary>
|
||||
OmronCipNet,
|
||||
/// <summary>
|
||||
/// 三菱 MC协议
|
||||
/// </summary>
|
||||
Mitsubishi,
|
||||
/// <summary>
|
||||
/// 基恩士 上位链路协议
|
||||
/// </summary>
|
||||
Keyence,
|
||||
/// <summary>
|
||||
/// 西门子 S7协议
|
||||
/// </summary>
|
||||
Siemens
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using PLCCommunication;
|
||||
using PLCCommunication.PLCType.Siemens;
|
||||
using PLCCommunication.Common;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Net;
|
||||
using PLCCommunication.Common.DataConvert;
|
||||
|
||||
namespace PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// 西门子S7协议通讯(S7-1200/S7-300/S7-400/S7-200SMART)
|
||||
/// </summary>
|
||||
[Export("SiemensS7", typeof(PlcReadWriteBase))]
|
||||
public class SiemensS7 : PlcReadWriteBase
|
||||
{
|
||||
private SiemensS7Net siemensS7Net = null;
|
||||
|
||||
public SiemensS7(int pid, string pname, IPEndPoint iep, int timeout = 10)
|
||||
: base(pid, pname, iep, timeout)
|
||||
{
|
||||
siemensS7Net = new SiemensS7Net(SiemensPLCS.S1200);
|
||||
siemensS7Net.IpAddress = iep.Address.ToString();
|
||||
siemensS7Net.Port = iep.Port;
|
||||
siemensS7Net.ByteTransform.DataFormat = DataFormat.CDAB;
|
||||
siemensS7Net.ConnectTimeOut = 2000;
|
||||
siemensS7Net.ReceiveTimeOut = 2000;
|
||||
IsConnected = false;
|
||||
}
|
||||
|
||||
public override bool Connect(ref string msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
JYResult connect = siemensS7Net.ConnectServer();
|
||||
if (connect.IsSuccess)
|
||||
{
|
||||
IsConnected = true;
|
||||
msg = "连接成功";
|
||||
return true;
|
||||
}
|
||||
|
||||
msg = connect.Message;
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.Message;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Disconnect()
|
||||
{
|
||||
if (IsConnected)
|
||||
{
|
||||
siemensS7Net.ConnectClose();
|
||||
IsConnected = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool ReadBool(string address)
|
||||
{
|
||||
JYResult<bool> result = siemensS7Net.ReadBool(address);
|
||||
return result.IsSuccess ? result.Content : false;
|
||||
}
|
||||
|
||||
public override short ReadInt16(string address)
|
||||
{
|
||||
JYResult<short> result = siemensS7Net.ReadInt16(address);
|
||||
return result.IsSuccess ? result.Content : (short)0;
|
||||
}
|
||||
|
||||
public override async Task<JYResult<short>> ReadInt16Async(string address)
|
||||
{
|
||||
return await siemensS7Net.ReadInt16Async(address);
|
||||
}
|
||||
|
||||
public override short[] ReadArrInt16(string address, ushort length)
|
||||
{
|
||||
JYResult<short[]> result = siemensS7Net.ReadInt16(address, length);
|
||||
return result.IsSuccess ? result.Content : null;
|
||||
}
|
||||
|
||||
public override async Task<JYResult<short[]>> ReadArrInt16Async(string address, ushort length)
|
||||
{
|
||||
return await siemensS7Net.ReadInt16Async(address, length);
|
||||
}
|
||||
|
||||
public override int ReadInt32(string address)
|
||||
{
|
||||
JYResult<int> result = siemensS7Net.ReadInt32(address);
|
||||
return result.IsSuccess ? result.Content : 0;
|
||||
}
|
||||
|
||||
public override float ReadFloat(string address)
|
||||
{
|
||||
JYResult<float> result = siemensS7Net.ReadFloat(address);
|
||||
return result.IsSuccess ? result.Content : 0.0f;
|
||||
}
|
||||
|
||||
public override float[] ReadArrFloat(string address, ushort length = 0)
|
||||
{
|
||||
JYResult<float[]> result = siemensS7Net.ReadFloat(address, length);
|
||||
return result.IsSuccess ? result.Content : null;
|
||||
}
|
||||
|
||||
public override async Task<JYResult<int>> ReadInt32Async(string address)
|
||||
{
|
||||
return await siemensS7Net.ReadInt32Async(address);
|
||||
}
|
||||
|
||||
public override async Task<JYResult<float[]>> ReadArrFloatAsync(string address, ushort length)
|
||||
{
|
||||
return await siemensS7Net.ReadFloatAsync(address, length);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 统一读取
|
||||
/// </summary>
|
||||
public override T ReadValue<T>(string address, DataType type, ushort length = 0)
|
||||
{
|
||||
object obj = null;
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataType.Bool:
|
||||
obj = siemensS7Net.ReadBool(address).Content;
|
||||
break;
|
||||
case DataType.Short:
|
||||
obj = siemensS7Net.ReadInt16(address).Content;
|
||||
break;
|
||||
case DataType.Int:
|
||||
obj = siemensS7Net.ReadInt32(address).Content;
|
||||
break;
|
||||
case DataType.Float:
|
||||
obj = siemensS7Net.ReadFloat(address).Content;
|
||||
break;
|
||||
case DataType.Double:
|
||||
obj = siemensS7Net.ReadDouble(address).Content;
|
||||
break;
|
||||
case DataType.String:
|
||||
obj = siemensS7Net.ReadString(address, length).Content;
|
||||
break;
|
||||
|
||||
case DataType.ArrByte:
|
||||
obj = ReadArrByteFromPlc(address, length);
|
||||
break;
|
||||
|
||||
case DataType.ArrFloat:
|
||||
obj = siemensS7Net.ReadFloat(address, length).Content;
|
||||
break;
|
||||
case DataType.ArrShort:
|
||||
obj = siemensS7Net.ReadInt16(address, length).Content;
|
||||
break;
|
||||
case DataType.ArrUshort:
|
||||
obj = siemensS7Net.ReadUInt16(address, length).Content;
|
||||
break;
|
||||
case DataType.ArrInt:
|
||||
obj = siemensS7Net.ReadInt32(address, length).Content;
|
||||
break;
|
||||
case DataType.ArrUint:
|
||||
obj = siemensS7Net.ReadUInt32(address, length).Content;
|
||||
break;
|
||||
}
|
||||
return (T)obj;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private byte[] ReadArrByteFromPlc(string address, ushort length)
|
||||
{
|
||||
short[] shorts = ReadArrInt16(address, length);
|
||||
if (shorts == null) return null;
|
||||
|
||||
byte[] bytes = new byte[shorts.Length * 2];
|
||||
Buffer.BlockCopy(shorts, 0, bytes, 0, bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public override bool WriteBool(string address, bool value)
|
||||
{
|
||||
JYResult result = siemensS7Net.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
public override bool WriteInt16(string address, short value)
|
||||
{
|
||||
JYResult result = siemensS7Net.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
public override bool WriteInt32(string address, int value)
|
||||
{
|
||||
JYResult result = siemensS7Net.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
public override bool WriteFloat(string address, float value)
|
||||
{
|
||||
JYResult result = siemensS7Net.Write(address, value);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
public override JYResult WriteValue(string address, object value, DataType type = DataType.Short)
|
||||
{
|
||||
JYResult result = new JYResult();
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataType.Bool:
|
||||
result = siemensS7Net.Write(address, (bool)value);
|
||||
break;
|
||||
case DataType.Short:
|
||||
result = siemensS7Net.Write(address, (short)value);
|
||||
break;
|
||||
case DataType.Int:
|
||||
result = siemensS7Net.Write(address, (int)value);
|
||||
break;
|
||||
case DataType.Float:
|
||||
result = siemensS7Net.Write(address, (float)value);
|
||||
break;
|
||||
case DataType.Double:
|
||||
result = siemensS7Net.Write(address, (double)value);
|
||||
break;
|
||||
case DataType.String:
|
||||
result = siemensS7Net.Write(address, value.ToString());
|
||||
break;
|
||||
case DataType.ArrShort:
|
||||
result = siemensS7Net.Write(address, (short[])value);
|
||||
break;
|
||||
case DataType.ArrUshort:
|
||||
result = siemensS7Net.Write(address, (ushort[])value);
|
||||
break;
|
||||
case DataType.ArrByte:
|
||||
result = siemensS7Net.Write(address, (byte[])value);
|
||||
break;
|
||||
case DataType.ArrFloat:
|
||||
result = siemensS7Net.Write(address, (float[])value);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.Message = ex.Message;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("PLC")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("PLC")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("486aecd0-c2bf-43c5-b7d7-88e565ade4b7")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.2")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.2")]
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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-6.0.0.0" newVersion="6.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.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Security.Cryptography.Xml" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.1" newVersion="6.0.0.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup></configuration>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user