2016-01-20 update 2 add comment and change all code to visual studio 2015 and .net framework 4.6

This commit is contained in:
parallelbgls@outlook.com
2016-01-20 17:25:04 +08:00
parent 089e88d1bf
commit fcb4432a98
36 changed files with 688 additions and 465 deletions

View File

@@ -13,13 +13,15 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CrossLampControl.WebApi</RootNamespace>
<AssemblyName>CrossLampControl.WebApi</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<TargetFrameworkProfile />
<UseGlobalApplicationHostFile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -42,13 +44,13 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Abstractions" />
<Reference Include="System.Web.Routing" />
@@ -102,6 +104,7 @@
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.0\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="WebGrease">
<Private>True</Private>
<HintPath>..\packages\WebGrease.1.5.2\lib\WebGrease.dll</HintPath>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
@@ -11,10 +11,18 @@
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-CrossLampControl.WebApi-20140912112502.mdf;Initial Catalog=aspnet-CrossLampControl.WebApi-20140912112502;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
<appSettings></appSettings>
<appSettings/>
<!--
有关 web.config 更改的说明,请参见 http://go.microsoft.com/fwlink/?LinkId=235367。
可在 <httpRuntime> 标记上设置以下特性。
<system.Web>
<httpRuntime targetFramework="4.6" />
</system.Web>
-->
<system.web>
<authentication mode="None"/>
<compilation debug="true" targetFramework="4.5" />
<compilation debug="true" targetFramework="4.6"/>
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.webServer>

View File

@@ -4,11 +4,22 @@ using System.Linq;
namespace ModBus.Net
{
/// <summary>
/// 地址组合器,组合后的每一组地址将只需一次向设备进行通讯
/// </summary>
public abstract class AddressCombiner
{
/// <summary>
/// 组合地址
/// </summary>
/// <param name="addresses">需要进行组合的地址</param>
/// <returns>组合完成后与设备通讯的地址</returns>
public abstract IEnumerable<CommunicationUnit> Combine(IEnumerable<AddressUnit> addresses);
}
/// <summary>
/// 连续的地址将组合成一组,向设备进行通讯
/// </summary>
public class AddressCombinerContinus : AddressCombiner
{
public override IEnumerable<CommunicationUnit> Combine(IEnumerable<AddressUnit> addresses)

View File

@@ -2,11 +2,23 @@
namespace ModBus.Net
{
/// <summary>
/// 地址编码器
/// </summary>
public abstract class AddressFormater
{
/// <summary>
/// 编码地址
/// </summary>
/// <param name="area">地址所在的数据区域</param>
/// <param name="address">地址</param>
/// <returns>编码后的地址</returns>
public abstract string FormatAddress(string area, int address);
}
/// <summary>
/// 基本的地址编码器
/// </summary>
public class AddressFormaterBase : AddressFormater
{
public override string FormatAddress(string area, int address)

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace ModBus.Net
{
/// <summary>
/// 数据单元翻译器
/// 地址翻译器
/// </summary>
public abstract class AddressTranslator
{
@@ -18,7 +18,7 @@ namespace ModBus.Net
}
/// <summary>
/// 基本的单元转换
/// 基本的地址翻译
/// </summary>
public class AddressTranslatorBase : AddressTranslator
{

View File

@@ -13,6 +13,12 @@ namespace ModBus.Net
TaskContinuationOptions.None,
TaskScheduler.Default);
/// <summary>
/// Run async method syncronized
/// </summary>
/// <typeparam name="TResult">Return type</typeparam>
/// <param name="func">Async method with return</param>
/// <returns>Return value</returns>
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return AsyncHelper._myTaskFactory
@@ -22,6 +28,10 @@ namespace ModBus.Net
.GetResult();
}
/// <summary>
/// Run async method syncronized.
/// </summary>
/// <param name="func">Async method</param>
public static void RunSync(Func<Task> func)
{
AsyncHelper._myTaskFactory
@@ -31,6 +41,12 @@ namespace ModBus.Net
.GetResult();
}
/// <summary>
/// Change async task to async task with cancellation token
/// </summary>
/// <param name="task">Async task</param>
/// <param name="token">Cancellation Token</param>
/// <returns>Task with Cancellation token</returns>
public static Task WithCancellation(this Task task,
CancellationToken token)
{
@@ -44,8 +60,8 @@ namespace ModBus.Net
}
}
/// <summary>AsyncLock locks across one or several await calls.
///
/// <summary>
/// AsyncLock locks across one or several await calls.
/// </summary>
public class AsyncLock
{
@@ -58,6 +74,10 @@ namespace ModBus.Net
_releaser = Task.FromResult(new Releaser(this));
}
/// <summary>
/// Lock the async method. Call like: using (await asynclock.LockAsync())
/// </summary>
/// <returns></returns>
public Task<Releaser> LockAsync()
{
var wait = _semaphore.WaitAsync();
@@ -88,6 +108,9 @@ namespace ModBus.Net
}
}
/// <summary>
/// AsyncSemaphore semaphore the multi run tasks.
/// </summary>
public class AsyncSemaphore
{
private readonly static Task _completed = Task.FromResult(true);

View File

@@ -5,6 +5,9 @@ namespace ModBus.Net
{
public abstract class BaseConnector
{
/// <summary>
/// 标识Connector的连接关键字
/// </summary>
public abstract string ConnectionToken { get; }
/// <summary>
/// 是否处于连接状态
@@ -13,41 +16,41 @@ namespace ModBus.Net
/// <summary>
/// 连接PLC
/// </summary>
/// <returns></returns>
/// <returns>是否连接成功</returns>
public abstract bool Connect();
/// <summary>
/// 连接PLC异步
/// </summary>
/// /// <returns></returns>
/// <returns>是否连接成功</returns>
public abstract Task<bool> ConnectAsync();
/// <summary>
/// 断开PLC
/// </summary>
/// <returns></returns>
/// <returns>是否断开成功</returns>
public abstract bool Disconnect();
/// <summary>
/// 无返回发送数据
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract bool SendMsgWithoutReturn(byte[] message);
/// <summary>
/// 无返回发送数据,异步
/// 无返回发送数据
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract Task<bool> SendMsgWithoutReturnAsync(byte[] message);
/// <summary>
/// 带返回发送数据
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract byte[] SendMsg(byte[] message);
/// <summary>
/// 带返回发送数据,异步
/// 带返回发送数据
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract Task<byte[]> SendMsgAsync(byte[] message);
}
}

View File

@@ -5,84 +5,136 @@ using System.Threading.Tasks;
namespace ModBus.Net
{
/// <summary>
/// 向设备设置值的方式
/// </summary>
public enum MachineSetDataType
{
/// <summary>
/// 地址
/// </summary>
Address,
/// <summary>
/// 通讯标识
/// </summary>
CommunicationTag
}
public abstract class BaseMachine : IMachineProperty
{
/// <summary>
/// 设备的Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 设备所在工程的名称
/// </summary>
public string ProjectName { get; set; }
/// <summary>
/// 设备的名称
/// </summary>
public string MachineName { get; set; }
public bool IsConnected
{
get
{
return BaseUtility.IsConnected;
}
}
/// <summary>
/// 是否处于连接状态
/// </summary>
public bool IsConnected => BaseUtility.IsConnected;
public string ConnectionToken
{
get { return BaseUtility.ConnectionToken; }
}
/// <summary>
/// 标识设备的连接关键字
/// </summary>
public string ConnectionToken => BaseUtility.ConnectionToken;
/// <summary>
/// 地址编码器
/// </summary>
public AddressFormater AddressFormater { get; set; }
/// <summary>
/// 地址解码器
/// </summary>
public AddressCombiner AddressCombiner { get; set; }
/// <summary>
/// 地址转换器
/// </summary>
public AddressTranslator AddressTranslator
{
get { return BaseUtility.AddressTranslator; }
set { BaseUtility.AddressTranslator = value; }
}
public MachineExtend MachineExtend { get; set; }
protected IEnumerable<CommunicationUnit> CommunicateAddresses
{
get { return AddressCombiner.Combine(GetAddresses); }
}
/// <summary>
/// 与设备实际通讯的连续地址
/// </summary>
protected IEnumerable<CommunicationUnit> CommunicateAddresses => AddressCombiner.Combine(GetAddresses);
/// <summary>
/// 描述需要与设备通讯的地址
/// </summary>
public IEnumerable<AddressUnit> GetAddresses { get; set; }
/// <summary>
/// 是否保持连接
/// </summary>
public bool KeepConnect { get; set; }
/// <summary>
/// 设备的连接器
/// </summary>
protected BaseUtility BaseUtility { get; set; }
/// <summary>
/// 构造器
/// </summary>
/// <param name="getAddresses">需要与设备通讯的地址</param>
protected BaseMachine(IEnumerable<AddressUnit> getAddresses)
: this(getAddresses, false)
{
}
/// <summary>
/// 构造器
/// </summary>
/// <param name="getAddresses">需要与设备通讯的地址</param>
/// <param name="keepConnect">是否保持连接</param>
protected BaseMachine(IEnumerable<AddressUnit> getAddresses, bool keepConnect)
{
GetAddresses = getAddresses;
KeepConnect = keepConnect;
}
/// <summary>
/// 读取数据
/// </summary>
/// <returns>从设备读取的数据</returns>
public Dictionary<string, ReturnUnit> GetDatas()
{
return AsyncHelper.RunSync(GetDatasAsync);
}
/// <summary>
/// 读取数据
/// </summary>
/// <returns>从设备读取的数据</returns>
public async Task<Dictionary<string,ReturnUnit>> GetDatasAsync()
{
try
{
Dictionary<string, ReturnUnit> ans = new Dictionary<string, ReturnUnit>();
//检测并连接设备
if (!BaseUtility.IsConnected)
{
await BaseUtility.ConnectAsync();
}
//如果无法连接,终止
if (!BaseUtility.IsConnected) return null;
//遍历每一个实际向设备获取数据的连续地址
foreach (var communicateAddress in CommunicateAddresses)
{
//获取数据
var datas =
await
BaseUtility.GetDatasAsync<byte>(2, 0,
@@ -91,15 +143,19 @@ namespace ModBus.Net
Math.Ceiling(communicateAddress.GetCount*
BigEndianValueHelper.Instance.ByteLength[
communicateAddress.DataType.FullName]));
//如果没有数据,终止
if (datas == null || datas.Length == 0) return null;
int pos = 0;
//解码数据
while (pos < communicateAddress.GetCount)
{
//获取地址
var address =
GetAddresses.SingleOrDefault(
p => p.Area == communicateAddress.Area && p.Address == pos + communicateAddress.Address);
if (address != null)
{
//将获取的数据和对应的通讯标识对应
ans.Add(address.CommunicationTag,
new ReturnUnit
{
@@ -116,10 +172,12 @@ namespace ModBus.Net
}
}
}
//如果不保持连接,断开连接
if (!KeepConnect)
{
BaseUtility.Disconnect();
}
//返回数据
if (ans.Count == 0) ans = null;
return ans;
}
@@ -130,23 +188,39 @@ namespace ModBus.Net
}
}
/// <summary>
/// 写入数据
/// </summary>
/// <param name="setDataType">写入类型</param>
/// <param name="values">需要写入的数据字典当写入类型为Address时键为需要写入的地址当写入类型为CommunicationTag时键为需要写入的单元的描述</param>
/// <returns>是否写入成功</returns>
public bool SetDatas(MachineSetDataType setDataType, Dictionary<string, double> values)
{
return AsyncHelper.RunSync(() => SetDatasAsync(setDataType, values));
}
/// <summary>
/// 写入数据
/// </summary>
/// <param name="setDataType">写入类型</param>
/// <param name="values">需要写入的数据字典当写入类型为Address时键为需要写入的地址当写入类型为CommunicationTag时键为需要写入的单元的描述</param>
/// <returns>是否写入成功</returns>
public async Task<bool> SetDatasAsync(MachineSetDataType setDataType, Dictionary<string, double> values)
{
try
{
//检测并连接设备
if (!BaseUtility.IsConnected)
{
await BaseUtility.ConnectAsync();
}
//如果设备无法连接,终止
if (!BaseUtility.IsConnected) return false;
List<AddressUnit> addresses = new List<AddressUnit>();
//遍历每个要设置的值
foreach (var value in values)
{
//根据设置类型找到对应的地址描述
AddressUnit address = null;
switch (setDataType)
{
@@ -166,32 +240,44 @@ namespace ModBus.Net
if (address == null) return false;
addresses.Add(address);
}
//将地址编码成与实际设备通讯的地址,注意这个地址必须是连续的
var communcationUnits = new AddressCombinerContinus().Combine(addresses);
//遍历每条通讯的连续地址
foreach (var communicateAddress in communcationUnits)
{
List<object> datasList = new List<object>();
//需要设置的字节数,计数
var setCount = (int)
Math.Ceiling(communicateAddress.GetCount*
BigEndianValueHelper.Instance.ByteLength[
communicateAddress.DataType.FullName]);
//总数
var allBytes = setCount;
//编码开始地址
var addressStart = AddressFormater.FormatAddress(communicateAddress.Area,
communicateAddress.Address);
while (setCount > 0)
{
//编码当前地址
var address = AddressFormater.FormatAddress(communicateAddress.Area,
communicateAddress.Address + allBytes - setCount);
//找到对应的描述地址
var addressUnit =
GetAddresses.SingleOrDefault(
p =>
p.Area == communicateAddress.Area &&
p.Address == communicateAddress.Address + allBytes - setCount);
//如果没有相应地址,跳过
if (addressUnit == null) continue;
//获取写入类型
Type dataType = addressUnit.DataType;
switch (setDataType)
{
case MachineSetDataType.Address:
{
//获取要写入的值
var value = values.SingleOrDefault(p => p.Key == address);
//将要写入的值加入队列
datasList.Add(Convert.ChangeType(value.Value, dataType));
break;
}
@@ -204,7 +290,7 @@ namespace ModBus.Net
}
setCount -= (int) BigEndianValueHelper.Instance.ByteLength[dataType.FullName];
}
//写入数据
await BaseUtility.SetDatasAsync(2, 0, addressStart, datasList.ToArray());
}
}
@@ -216,23 +302,41 @@ namespace ModBus.Net
return true;
}
/// <summary>
/// 连接设备
/// </summary>
/// <returns>是否连接成功</returns>
public bool Connect()
{
return BaseUtility.Connect();
}
/// <summary>
/// 连接设备
/// </summary>
/// <returns>是否连接成功</returns>
public async Task<bool> ConnectAsync()
{
return await BaseUtility.ConnectAsync();
}
/// <summary>
/// 断开设备
/// </summary>
/// <returns>是否断开成功</returns>
public bool Disconnect()
{
return BaseUtility.Disconnect();
}
/// <summary>
/// 将获取的数据转换成可以向设备写入的数据格式
/// </summary>
/// <param name="getValues">获取的数据</param>
/// <returns>写入的数据</returns>
public static Dictionary<string, double> MapGetValuesToSetValues(Dictionary<string, ReturnUnit> getValues)
{
if (getValues == null) return null;
return (from getValue in getValues
select new KeyValuePair<string, double>(getValue.Key, getValue.Value.PlcValue)).ToDictionary(p=>p.Key,p=>p.Value);
}
@@ -251,51 +355,93 @@ namespace ModBus.Net
}
}
/// <summary>
/// 通讯单元
/// </summary>
public class CommunicationUnit
{
/// <summary>
/// 区域
/// </summary>
public string Area { get; set; }
/// <summary>
/// 地址
/// </summary>
public int Address { get; set; }
/// <summary>
/// 获取个数
/// </summary>
public int GetCount { get; set; }
/// <summary>
/// 数据类型
/// </summary>
public Type DataType { get; set; }
}
/// <summary>
/// 数据单元扩展,返回数据时会同时将其返回
/// </summary>
public class UnitExtend
{
}
public class MachineExtend
{
}
/// <summary>
/// 返回的数据单元
/// </summary>
public class ReturnUnit
{
/// <summary>
/// 返回的数据
/// </summary>
public double PlcValue { get; set; }
/// <summary>
/// 数据的扩展
/// </summary>
public UnitExtend UnitExtend { get; set; }
}
public class AddressUnit
{
/// <summary>
/// 数据单元Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 数据所属的区域Modbus指通讯码PROFINET指数据块
/// 数据所属的区域
/// </summary>
public string Area { get; set; }
/// <summary>
/// 地址
/// </summary>
public int Address { get; set; }
/// <summary>
/// 数据类型
/// </summary>
public Type DataType { get; set; }
/// <summary>
/// 放缩比例
/// </summary>
public double Zoom { get; set; }
/// <summary>
/// 小数位数
/// </summary>
public int DecimalPos { get; set; }
/// <summary>
/// 通讯标识名称
/// </summary>
public string CommunicationTag { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 单位
/// </summary>
public string Unit { get; set; }
/// <summary>
/// 扩展
/// </summary>
public UnitExtend UnitExtend { get; set; }
}
@@ -312,11 +458,26 @@ namespace ModBus.Net
}
}
/// <summary>
/// 设备的抽象
/// </summary>
public interface IMachineProperty
{
/// <summary>
/// Id
/// </summary>
int Id { get; set; }
/// <summary>
/// 工程名
/// </summary>
string ProjectName { get; set; }
/// <summary>
/// 设备名
/// </summary>
string MachineName { get; set; }
/// <summary>
/// 标识设备的连接关键字
/// </summary>
string ConnectionToken { get; }
}
}

View File

@@ -11,12 +11,13 @@ namespace ModBus.Net
public abstract class BaseProtocal
{
/// <summary>
/// 发送数据
/// 协议的连接器
/// </summary>
/// <param name="content">需要发送的数据</param>
/// <returns>数据是否正确接收</returns>
public ProtocalLinker ProtocalLinker { get; protected set; }
/// <summary>
/// 构造器
/// </summary>
protected BaseProtocal()
{
Protocals = new Dictionary<string, ProtocalUnit>();
@@ -25,8 +26,8 @@ namespace ModBus.Net
/// <summary>
/// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议
/// </summary>
/// <param name="protocalName">协议的类的名称</param>
/// <returns></returns>
/// <param name="type">协议的类的GetType</param>
/// <returns>协议的实例</returns>
public ProtocalUnit this[Type type]
{
get
@@ -45,8 +46,15 @@ namespace ModBus.Net
}
}
protected Dictionary<string, ProtocalUnit> Protocals { get; private set; }
/// <summary>
/// 协议集合
/// </summary>
protected Dictionary<string, ProtocalUnit> Protocals { get; }
/// <summary>
/// 注册一个协议
/// </summary>
/// <param name="linkProtocal">需要注册的协议</param>
protected void Register(ProtocalUnit linkProtocal)
{
if (linkProtocal == null) return;
@@ -56,71 +64,59 @@ namespace ModBus.Net
/// <summary>
/// 发送协议内容并接收,一般方法
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
/// <param name="content">写入的内容,使用对象数组描述</param>
/// <returns>从设备获取的字节流</returns>
public virtual byte[] SendReceive(params object[] content)
{
return AsyncHelper.RunSync(() => SendReceiveAsync(content));
}
/// <summary>
/// 发送协议内容并接收,一般方法(异步)
/// 发送协议内容并接收,一般方法
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
/// <param name="content">写入的内容,使用对象数组描述</param>
/// <returns>从设备获取的字节流</returns>
public virtual async Task<byte[]> SendReceiveAsync(params object[] content)
{
if (ProtocalLinker == null || !ProtocalLinker.IsConnected)
{
await ConnectAsync();
}
if (ProtocalLinker != null)
{
return await ProtocalLinker.SendReceiveAsync(ProtocalUnit.TranslateContent(content));
}
else
{
return null;
}
}
/// <summary>
/// 发送协议,通过传入需要使用的协议内容和输入结构
/// </summary>
/// <param name="unit"></param>
/// <param name="content"></param>
/// <returns></returns>
/// <param name="unit">协议的实例</param>
/// <param name="content">输入信息的结构化描述</param>
/// <returns>输出信息的结构化描述</returns>
public virtual OutputStruct SendReceive(ProtocalUnit unit, InputStruct content)
{
int t = 0;
//如果为特别处理协议的话,跳过协议扩展收缩
var formatContent = unit.Format(content);
if (formatContent != null)
{
byte[] receiveContent;
if (unit is SpecialProtocalUnit)
{
receiveContent = ProtocalLinker.SendReceiveWithoutExtAndDec(formatContent);
}
else
{
receiveContent = ProtocalLinker.SendReceive(formatContent);
}
if (receiveContent != null)
{
return unit.Unformat(receiveContent, ref t);
}
}
return null;
return AsyncHelper.RunSync(() => SendReceiveAsync(unit, content));
}
/// <summary>
/// 发送协议,通过传入需要使用的协议内容和输入结构(异步)
/// 发送协议,通过传入需要使用的协议内容和输入结构
/// </summary>
/// <param name="unit"></param>
/// <param name="content"></param>
/// <returns></returns>
/// <param name="unit">协议的实例</param>
/// <param name="content">输入信息的结构化描述</param>
/// <returns>输出信息的结构化描述</returns>
public virtual async Task<OutputStruct> SendReceiveAsync(ProtocalUnit unit, InputStruct content)
{
int t = 0;
//如果为特别处理协议的话,跳过协议扩展收缩
var formatContent = unit.Format(content);
if (formatContent != null)
{
byte[] receiveContent;
//如果为特别处理协议的话,跳过协议扩展收缩
if (unit is SpecialProtocalUnit)
{
receiveContent = await ProtocalLinker.SendReceiveWithoutExtAndDecAsync(formatContent);

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ModBus.Net
@@ -12,26 +13,29 @@ namespace ModBus.Net
protected BaseProtocal Wrapper;
protected string ConnectionString { get; set; }
public bool IsConnected
{
get
{
if (Wrapper == null || Wrapper.ProtocalLinker == null) return false;
return Wrapper.ProtocalLinker.IsConnected;
}
}
/// <summary>
/// 设备是否已经连接
/// </summary>
public bool IsConnected => Wrapper?.ProtocalLinker != null && Wrapper.ProtocalLinker.IsConnected;
public string ConnectionToken
{
get { return Wrapper.ProtocalLinker.ConnectionToken; }
}
/// <summary>
/// 标识设备的连接关键字
/// </summary>
public string ConnectionToken => Wrapper.ProtocalLinker.ConnectionToken;
/// <summary>
/// 地址翻译器
/// </summary>
public AddressTranslator AddressTranslator { get; set; }
/// <summary>
/// 构造器
/// </summary>
protected BaseUtility()
{
AddressTranslator = new AddressTranslatorBase();
}
/// <summary>
/// 设置连接类型
/// </summary>
@@ -44,7 +48,7 @@ namespace ModBus.Net
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取类型和个数</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的byte数据</returns>
protected virtual byte[] GetDatas(byte belongAddress, byte masterAddress, string startAddress, int getByteCount)
{
@@ -52,32 +56,37 @@ namespace ModBus.Net
}
/// <summary>
/// 获取数据(异步)
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取类型和个数</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的byte数据</returns>
protected abstract Task<byte[]> GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount);
/// <summary>
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCount">获取类型和个数</param>
/// <returns>接收到的对应的类型和数据</returns>
public virtual object[] GetDatas(byte belongAddress, byte masterAddress, string startAddress,
KeyValuePair<Type, int> getTypeAndCount)
{
try
{
string typeName = getTypeAndCount.Key.FullName;
double bCount = BigEndianValueHelper.Instance.ByteLength[typeName];
byte[] getBytes = GetDatas(belongAddress, masterAddress, startAddress,
(int) Math.Ceiling(bCount*getTypeAndCount.Value));
return BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCount);
}
catch (Exception)
{
return null;
}
return AsyncHelper.RunSync(() => GetDatasAsync(belongAddress, masterAddress, startAddress, getTypeAndCount));
}
/// <summary>
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCount">获取类型和个数</param>
/// <returns>接收到的对应的类型和数据</returns>
public virtual async Task<object[]> GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress,
KeyValuePair<Type, int> getTypeAndCount)
{
@@ -95,21 +104,30 @@ namespace ModBus.Net
}
}
/// <summary>
/// 获取数据
/// </summary>
/// <typeparam name="T">需要接收的类型</typeparam>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的对应的类型和数据</returns>
public virtual T[] GetDatas<T>(byte belongAddress, byte masterAddress, string startAddress,
int getByteCount)
{
try
{
var getBytes = GetDatas(belongAddress, masterAddress, startAddress,
new KeyValuePair<Type, int>(typeof (T), getByteCount));
return BigEndianValueHelper.Instance.ObjectArrayToDestinationArray<T>(getBytes);
}
catch (Exception)
{
return null;
}
return AsyncHelper.RunSync(() => GetDatasAsync<T>(belongAddress, masterAddress, startAddress, getByteCount));
}
/// <summary>
/// 获取数据
/// </summary>
/// <typeparam name="T">需要接收的类型</typeparam>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的对应的类型和数据</returns>
public virtual async Task<T[]> GetDatasAsync<T>(byte belongAddress, byte masterAddress, string startAddress,
int getByteCount)
{
@@ -125,41 +143,42 @@ namespace ModBus.Net
}
}
/// <summary>
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCountList">获取类型和个数的队列</param>
/// <returns>获取数据的对象数组,请强制转换成相应类型</returns>
public virtual object[] GetDatas(byte belongAddress, byte masterAddress, string startAddress,
IEnumerable<KeyValuePair<Type, int>> getTypeAndCountList)
{
try
{
int bAllCount = 0;
foreach (var getTypeAndCount in getTypeAndCountList)
{
string typeName = getTypeAndCount.Key.FullName;
double bCount = BigEndianValueHelper.Instance.ByteLength[typeName];
bAllCount += (int)Math.Ceiling(bCount * getTypeAndCount.Value);
}
byte[] getBytes = GetDatas(belongAddress, masterAddress, startAddress, bAllCount);
return BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCountList);
}
catch (Exception)
{
return null;
}
return
AsyncHelper.RunSync(() => GetDatasAsync(belongAddress, masterAddress, startAddress, getTypeAndCountList));
}
/// <summary>
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCountList">获取类型和个数的队列</param>
public virtual async Task<object[]> GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress,
IEnumerable<KeyValuePair<Type, int>> getTypeAndCountList)
{
try
{
int bAllCount = 0;
foreach (var getTypeAndCount in getTypeAndCountList)
{
string typeName = getTypeAndCount.Key.FullName;
double bCount = BigEndianValueHelper.Instance.ByteLength[typeName];
bAllCount += (int)Math.Ceiling(bCount * getTypeAndCount.Value);
}
var translateTypeAndCount = getTypeAndCountList as IList<KeyValuePair<Type, int>> ??
getTypeAndCountList.ToList();
int bAllCount = (
from getTypeAndCount in translateTypeAndCount
let typeName = getTypeAndCount.Key.FullName
let bCount = BigEndianValueHelper.Instance.ByteLength[typeName]
select (int) Math.Ceiling(bCount*getTypeAndCount.Value)).Sum();
byte[] getBytes = await GetDatasAsync(belongAddress, masterAddress, startAddress, bAllCount);
return BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCountList);
return BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, translateTypeAndCount);
}
catch (Exception)
{
@@ -181,7 +200,7 @@ namespace ModBus.Net
}
/// <summary>
/// 设置数据(异步)
/// 设置数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
@@ -207,16 +226,28 @@ namespace ModBus.Net
public abstract bool SetTime(byte belongAddress, DateTime setTime);
*/
/// <summary>
/// 连接设备
/// </summary>
/// <returns>设备是否连接成功</returns>
public bool Connect()
{
return Wrapper.Connect();
}
/// <summary>
/// 连接设备
/// </summary>
/// <returns>设备是否连接成功</returns>
public async Task<bool> ConnectAsync()
{
return await Wrapper.ConnectAsync();
}
/// <summary>
/// 断开设备
/// </summary>
/// <returns>设备是否断开成功</returns>
public bool Disconnect()
{
return Wrapper.Disconnect();

View File

@@ -38,35 +38,17 @@ namespace ModBus.Net.FBox
}
}
public string AuthorizeEndpoint
{
get { return BaseAddress + "/connect/authorize"; }
}
public string AuthorizeEndpoint => BaseAddress + "/connect/authorize";
public string LogoutEndpoint
{
get { return BaseAddress + "/connect/endsession"; }
}
public string LogoutEndpoint => BaseAddress + "/connect/endsession";
public string TokenEndpoint
{
get { return BaseAddress + "/connect/token"; }
}
public string TokenEndpoint => BaseAddress + "/connect/token";
public string UserInfoEndpoint
{
get {return BaseAddress + "/connect/userinfo"; }
}
public string UserInfoEndpoint => BaseAddress + "/connect/userinfo";
public string IdentityTokenValidationEndpoint
{
get {return BaseAddress + "/connect/identitytokenvalidation"; }
}
public string IdentityTokenValidationEndpoint => BaseAddress + "/connect/identitytokenvalidation";
public string TokenRevocationEndpoint
{
get {return BaseAddress + "/connect/revocation"; }
}
public string TokenRevocationEndpoint => BaseAddress + "/connect/revocation";
public string AspNetWebApiSampleApi
{

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace DelinRemoteControlBoxTest
namespace ModBus.Net.FBox
{
public class BoxGroup
{

View File

@@ -5,7 +5,8 @@ namespace ModBus.Net.FBox
{
public class FBoxMachine : BaseMachine
{
public FBoxMachine(FBoxType fBoxType, string connectionString, string localSequence, SignalRSigninMsg msg, IEnumerable<AddressUnit> getAddresses, bool keepConnect) : base(getAddresses, keepConnect)
public FBoxMachine(FBoxType fBoxType, string connectionString, string localSequence, SignalRSigninMsg msg,
IEnumerable<AddressUnit> getAddresses, bool keepConnect) : base(getAddresses, keepConnect)
{
AddressFormater = new AddressFormaterFBox();
AddressCombiner = new AddressCombinerFBox();

View File

@@ -66,9 +66,9 @@ namespace ModBus.Net.FBox
{
var readRequestFBoxInputStruct = new ReadRequestFBoxInputStruct(startAddress, (ushort)getByteCount, AddressTranslator);
var readRequestSiemensOutputStruct =
(ReadRequestFBoxOutputStruct)await
Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestFBoxProtocal)], readRequestFBoxInputStruct);
return readRequestSiemensOutputStruct.GetValue;
await
Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestFBoxProtocal)], readRequestFBoxInputStruct) as ReadRequestFBoxOutputStruct;
return readRequestSiemensOutputStruct?.GetValue;
}
catch (Exception)
{

View File

@@ -5,7 +5,6 @@ using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using DelinRemoteControlBoxTest;
using Microsoft.AspNet.SignalR.Client;
using Newtonsoft.Json;
using Thinktecture.IdentityModel.Client;
@@ -45,36 +44,18 @@ namespace ModBus.Net.FBox
private Timer _timer;
private string MachineId
{
get
{
return ConnectionToken.Split(',')[0];
}
}
private string MachineId => ConnectionToken.Split(',')[0];
private string LocalSequence {
get
{
return ConnectionToken.Split(',')[1];
}
}
private string LocalSequence => ConnectionToken.Split(',')[1];
private static readonly AsyncLock _lock = new AsyncLock();
private bool _connected;
public override bool IsConnected { get { return _connected; } }
public override bool IsConnected => _connected;
private SignalRSigninMsg Msg { get; set;}
private Constants _constants;
private Constants Constants
{
get
{
if (_constants == null) _constants = new Constants();
return _constants;
}
}
private Constants Constants => _constants ?? (_constants = new Constants());
public SignalRConnector(string machineId, string localSequence, SignalRSigninMsg msg)
{

View File

@@ -8,23 +8,23 @@
/// <summary>
/// 从输入结构格式化
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">结构化的输入数据</param>
/// <returns>格式化后的字节流</returns>
byte[] Format(InputStruct message);
/// <summary>
/// 从对象的参数数组格式化
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">非结构化的输入数据</param>
/// <returns>格式化后的字节流</returns>
byte[] Format(params object[] message);
/// <summary>
/// 把仪器返回的内容填充到输出结构中
/// </summary>
/// <param name="messageBytes"></param>
/// <param name="pos"></param>
/// <returns></returns>
/// <param name="messageBytes">返回数据的字节流</param>
/// <param name="pos">转换标记位</param>
/// <returns>结构化的输出数据</returns>
OutputStruct Unformat(byte[] messageBytes, ref int pos);
}
}

View File

@@ -9,8 +9,9 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ModBus.Net</RootNamespace>
<AssemblyName>ModBus.Net</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

View File

@@ -69,10 +69,12 @@ namespace ModBus.Net.Modbus
{
try
{
var inputStruct = new ReadDataModbusInputStruct(belongAddress, startAddress, getByteCount % 2 == 0 ? (ushort)(getByteCount / 2) : (ushort)(getByteCount / 2 + 1), AddressTranslator);
var inputStruct = new ReadDataModbusInputStruct(belongAddress, startAddress,
getByteCount%2 == 0 ? (ushort) (getByteCount/2) : (ushort) (getByteCount/2 + 1), AddressTranslator);
var outputStruct = await
Wrapper.SendReceiveAsync(Wrapper[typeof(ReadDataModbusProtocal)], inputStruct) as ReadDataModbusOutputStruct;
return outputStruct.DataValue;
Wrapper.SendReceiveAsync(Wrapper[typeof (ReadDataModbusProtocal)], inputStruct) as
ReadDataModbusOutputStruct;
return outputStruct?.DataValue;
}
catch
{
@@ -84,12 +86,12 @@ namespace ModBus.Net.Modbus
{
try
{
var inputStruct = new WriteDataModbusInputStruct(belongAddress, startAddress, setContents, AddressTranslator);
var inputStruct = new WriteDataModbusInputStruct(belongAddress, startAddress, setContents,
AddressTranslator);
var outputStruct = await
Wrapper.SendReceiveAsync(Wrapper[typeof (WriteDataModbusProtocal)], inputStruct) as
WriteDataModbusOutputStruct;
if (outputStruct.WriteCount != setContents.Length) return false;
return true;
return outputStruct?.WriteCount == setContents.Length;
}
catch
{
@@ -106,7 +108,7 @@ namespace ModBus.Net.Modbus
var outputStruct =
Wrapper.SendReceive(Wrapper[typeof(GetSystemTimeModbusProtocal)], inputStruct) as
GetSystemTimeModbusOutputStruct;
return outputStruct.Time;
return outputStruct?.Time;
}
catch (Exception)
{
@@ -122,7 +124,7 @@ namespace ModBus.Net.Modbus
var outputStruct =
Wrapper.SendReceive(Wrapper[typeof(SetSystemTimeModbusProtocal)], inputStruct) as
SetSystemTimeModbusOutputStruct;
return outputStruct.WriteCount > 0;
return outputStruct?.WriteCount > 0;
}
catch (Exception)
{

View File

@@ -10,31 +10,35 @@ namespace ModBus.Net
{
protected BaseConnector _baseConnector;
public string ConnectionToken
{
get { return _baseConnector.ConnectionToken; }
}
public string ConnectionToken => _baseConnector.ConnectionToken;
public bool IsConnected
{
get
{
if (_baseConnector == null)
return false;
return _baseConnector.IsConnected;
}
}
/// <summary>
/// 设备是否连接
/// </summary>
public bool IsConnected => _baseConnector != null && _baseConnector.IsConnected;
/// <summary>
/// 连接设备
/// </summary>
/// <returns>设备是否连接成功</returns>
public bool Connect()
{
return _baseConnector.Connect();
}
/// <summary>
/// 连接设备
/// </summary>
/// <returns>设备是否连接成功</returns>
public async Task<bool> ConnectAsync()
{
return await _baseConnector.ConnectAsync();
}
/// <summary>
/// 断开设备
/// </summary>
/// <returns>设备是否断开成功</returns>
public bool Disconnect()
{
return _baseConnector.Disconnect();
@@ -82,9 +86,8 @@ namespace ModBus.Net
//发送数据
byte[] receiveBytes = await _baseConnector.SendMsgAsync(content);
//容错处理
if (!CheckRight(receiveBytes)) return null;
return !CheckRight(receiveBytes) ? null : receiveBytes;
//返回字符
return receiveBytes;
}
/// <summary>
@@ -94,13 +97,10 @@ namespace ModBus.Net
/// <returns>协议是否是正确的</returns>
public virtual bool CheckRight(byte[] content)
{
if (content == null)
{
if (content != null) return true;
Disconnect();
return false;
}
return true;
}
/// <summary>
/// 协议内容扩展,发送时根据需要扩展
@@ -113,7 +113,7 @@ namespace ModBus.Net
ProtocalLinkerBytesExtend bytesExtend =
Assembly.Load(this.GetType().Assembly.GetName().Name).CreateInstance(this.GetType().FullName + "BytesExtend") as
ProtocalLinkerBytesExtend;
return bytesExtend.BytesExtend(content);
return bytesExtend?.BytesExtend(content);
}
/// <summary>
@@ -127,7 +127,7 @@ namespace ModBus.Net
ProtocalLinkerBytesExtend bytesExtend =
Assembly.Load(this.GetType().Assembly.GetName().Name).CreateInstance(this.GetType().FullName + "BytesExtend") as
ProtocalLinkerBytesExtend;
return bytesExtend.BytesDecact(content);
return bytesExtend?.BytesDecact(content);
}
}
}

View File

@@ -5,35 +5,35 @@ namespace ModBus.Net
public abstract class ProtocalUnit : IProtocalFormatting
{
/// <summary>
/// 格式化,将输入结构转换为字节数组
/// 从输入结构格式化
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">结构化的输入数据</param>
/// <returns>格式化后的字节流</returns>
public abstract byte[] Format(InputStruct message);
/// <summary>
/// 格式化,将对象数组转换为字节数组
/// 从对象的参数数组格式化
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
/// <param name="message">非结构化的输入数据</param>
/// <returns>格式化后的字节流</returns>
public virtual byte[] Format(params object[] message)
{
return TranslateContent(message);
}
/// <summary>
/// 结构化,将字节数组转换为输出结构
/// 把仪器返回的内容填充到输出结构
/// </summary>
/// <param name="messageBytes"></param>
/// <param name="pos"></param>
/// <returns></returns>
/// <param name="messageBytes">返回数据的字节流</param>
/// <param name="pos">转换标记位</param>
/// <returns>结构化的输出数据</returns>
public abstract OutputStruct Unformat(byte[] messageBytes, ref int pos);
/// <summary>
/// 转换静态方法,把对象数组转换为字节数组。
/// </summary>
/// <param name="contents"></param>
/// <returns></returns>
/// <param name="contents">对象数组</param>
/// <returns>字节数组</returns>
public static byte[] TranslateContent(params object[] contents)
{
return BigEndianValueHelper.Instance.ObjectArrayToByteArray(contents);

View File

@@ -4,15 +4,15 @@ namespace ModBus.Net.Siemens
{
public class SiemensTcpProtocal : SiemensProtocal
{
private ushort _taspSrc;
private ushort _tsapDst;
private ushort _maxCalling;
private ushort _maxCalled;
private ushort _maxPdu;
private byte _tdpuSize;
private readonly ushort _taspSrc;
private readonly ushort _tsapDst;
private readonly ushort _maxCalling;
private readonly ushort _maxCalled;
private readonly ushort _maxPdu;
private readonly byte _tdpuSize;
private string _ip;
private int connectTryCount;
private readonly string _ip;
private int _connectTryCount;
public SiemensTcpProtocal(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled, ushort maxPdu) : this(tdpuSize, tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ConfigurationManager.IP)
{
@@ -27,7 +27,7 @@ namespace ModBus.Net.Siemens
_maxPdu = maxPdu;
_tdpuSize = tdpuSize;
_ip = ip;
connectTryCount = 0;
_connectTryCount = 0;
}
public override byte[] SendReceive(params object[] content)
@@ -51,13 +51,10 @@ namespace ModBus.Net.Siemens
public override async Task<OutputStruct> SendReceiveAsync(ProtocalUnit unit, InputStruct content)
{
if (ProtocalLinker == null || !ProtocalLinker.IsConnected)
{
if (connectTryCount > 10) return null;
if (ProtocalLinker != null && ProtocalLinker.IsConnected) return await base.SendReceiveAsync(unit, content);
if (_connectTryCount > 10) return null;
return await await ConnectAsync().ContinueWith(answer => answer.Result ? base.SendReceiveAsync(unit, content) : null);
}
return await base.SendReceiveAsync(unit, content);
}
private async Task<OutputStruct> ForceSendReceiveAsync(ProtocalUnit unit, InputStruct content)
{
@@ -71,11 +68,10 @@ namespace ModBus.Net.Siemens
public override async Task<bool> ConnectAsync()
{
connectTryCount++;
_connectTryCount++;
ProtocalLinker = new SiemensTcpProtocalLinker(_ip);
if (await ProtocalLinker.ConnectAsync())
{
connectTryCount = 0;
if (!await ProtocalLinker.ConnectAsync()) return false;
_connectTryCount = 0;
var inputStruct = new CreateReferenceSiemensInputStruct(_tdpuSize, _taspSrc, _tsapDst);
return
await await
@@ -91,10 +87,8 @@ namespace ModBus.Net.Siemens
await
SendReceiveAsync(this[typeof (EstablishAssociationSiemensProtocal)],
inputStruct2);
return true;
return outputStruct2 != null;
});
}
return false;
}
}
}

View File

@@ -23,12 +23,12 @@ namespace ModBus.Net.Siemens
public class SiemensUtility : BaseUtility
{
private byte _tdpuSize;
private ushort _taspSrc;
private ushort _tsapDst;
private ushort _maxCalling;
private ushort _maxCalled;
private ushort _maxPdu;
private readonly byte _tdpuSize;
private readonly ushort _taspSrc;
private readonly ushort _tsapDst;
private readonly ushort _maxCalling;
private readonly ushort _maxCalled;
private readonly ushort _maxPdu;
private SiemensType _siemensType;
@@ -43,14 +43,14 @@ namespace ModBus.Net.Siemens
_siemensType = value;
switch (_siemensType)
{
case SiemensType.Ppi:
{
throw new NotImplementedException();
}
case SiemensType.Mpi:
{
throw new NotImplementedException();
}
//case SiemensType.Ppi:
// {
// throw new NotImplementedException();
// }
//case SiemensType.Mpi:
// {
// throw new NotImplementedException();
// }
case SiemensType.Tcp:
{
Wrapper = ConnectionString == null ? new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu) : new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu, ConnectionString);
@@ -88,6 +88,7 @@ namespace ModBus.Net.Siemens
}
case SiemensMachineModel.S7_1200:
case SiemensMachineModel.S7_1500:
case SiemensMachineModel.S7_200_Smart:
{
_tdpuSize = 0x09;
_taspSrc = 0x4b54;
@@ -97,6 +98,10 @@ namespace ModBus.Net.Siemens
_maxPdu = 0x00f0;
break;
}
default:
{
throw new NotImplementedException("没有相应的西门子类型");
}
}
ConnectionType = connectionType;
AddressTranslator = new AddressTranslatorSiemens();
@@ -113,9 +118,10 @@ namespace ModBus.Net.Siemens
{
var readRequestSiemensInputStruct = new ReadRequestSiemensInputStruct(0xd3c7, SiemensTypeCode.Byte, startAddress, (ushort)getByteCount, AddressTranslator);
var readRequestSiemensOutputStruct =
(ReadRequestSiemensOutputStruct) await
Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestSiemensProtocal)], readRequestSiemensInputStruct);
return readRequestSiemensOutputStruct.GetValue;
await
Wrapper.SendReceiveAsync(Wrapper[typeof (ReadRequestSiemensProtocal)],
readRequestSiemensInputStruct) as ReadRequestSiemensOutputStruct;
return readRequestSiemensOutputStruct?.GetValue;
}
catch (Exception)
{
@@ -129,12 +135,10 @@ namespace ModBus.Net.Siemens
{
var writeRequestSiemensInputStruct = new WriteRequestSiemensInputStruct(0xd3c8, startAddress, setContents, AddressTranslator);
var writeRequestSiemensOutputStruct =
(WriteRequestSiemensOutputStruct) await
Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestSiemensProtocal)], writeRequestSiemensInputStruct);
if (writeRequestSiemensOutputStruct.AccessResult == SiemensAccessResult.NoError)
return true;
else
return false;
await
Wrapper.SendReceiveAsync(Wrapper[typeof (WriteRequestSiemensProtocal)],
writeRequestSiemensInputStruct) as WriteRequestSiemensOutputStruct;
return writeRequestSiemensOutputStruct?.AccessResult == SiemensAccessResult.NoError;
}
catch (Exception)
{

View File

@@ -174,7 +174,7 @@ namespace ModBus.Net
/// </summary>
private HashSet<BaseMachine> _unlinkedMachines;
//private TaskFactory<Dictionary<string,ReturnUnit>> _tasks;
private TaskScheduler _scheduler;
//private TaskScheduler _scheduler;
//private CancellationTokenSource _cts;
/// <summary>
@@ -186,6 +186,9 @@ namespace ModBus.Net
/// </summary>
private Timer _timer2;
/// <summary>
/// 保持连接
/// </summary>
private bool _keepConnect;
/// <summary>
@@ -208,10 +211,20 @@ namespace ModBus.Net
}
}
/// <summary>
/// 返回数据代理
/// </summary>
/// <param name="returnValue"></param>
public delegate void ReturnValuesDelegate(KeyValuePair<int, Dictionary<string,ReturnUnit>> returnValue);
/// <summary>
/// 返回数据事件
/// </summary>
public event ReturnValuesDelegate ReturnValues;
/// <summary>
/// 获取间隔
/// </summary>
private int _getCycle;
/// <summary>
@@ -345,13 +358,17 @@ namespace ModBus.Net
}
}
/// <summary>
/// 将设备指定为未连接
/// </summary>
/// <param name="id">设备的id</param>
public void MoveMachineToUnlinked(int id)
{
IEnumerable<BaseMachine> machines;
lock(_machines)
{
machines = _machines.Where(c => c.Id == id).ToList();
if (machines.Count() <= 0) return;
if (!machines.Any()) return;
_machines.RemoveWhere(p => p.Id == id);
}
lock(_unlinkedMachines)
@@ -363,13 +380,17 @@ namespace ModBus.Net
}
}
/// <summary>
/// 将设备指定为已连接
/// </summary>
/// <param name="id">设备的id</param>
public void MoveMachineToLinked(int id)
{
IEnumerable<BaseMachine> machines;
lock (_unlinkedMachines)
{
machines = _unlinkedMachines.Where(c => c.Id == id).ToList();
if (machines.Count() <= 0) return;
if (!machines.Any()) return;
_unlinkedMachines.RemoveWhere(p => p.Id == id);
}
lock (_machines)
@@ -397,20 +418,32 @@ namespace ModBus.Net
}
}
/// <summary>
/// 已连接设备更新
/// </summary>
/// <param name="sender"></param>
private void MaintainTasks(object sender)
{
AsyncHelper.RunSync(MaintainTasksAsync);
}
/// <summary>
/// 未连接设备更新
/// </summary>
/// <param name="sender"></param>
private void MaintainTasks2(object sender)
{
AsyncHelper.RunSync(MaintainTasks2Async);
}
/// <summary>
/// 已连接设备更新
/// </summary>
/// <returns></returns>
private async Task MaintainTasksAsync()
{
HashSet<BaseMachine> saveMachines = new HashSet<BaseMachine>();
IEnumerable<BaseMachine> saveMachinesEnum = new List<BaseMachine>();
IEnumerable<BaseMachine> saveMachinesEnum;
lock (_machines)
{
saveMachines.UnionWith(_machines);
@@ -422,6 +455,10 @@ namespace ModBus.Net
}
}
/// <summary>
/// 未连接设备更新
/// </summary>
/// <returns></returns>
private async Task MaintainTasks2Async()
{
HashSet<BaseMachine> saveMachines = new HashSet<BaseMachine>();
@@ -444,18 +481,28 @@ namespace ModBus.Net
}
}
public async Task<bool> SetDatasAsync(string machineToken, MachineSetDataType setDataType,
/// <summary>
/// 设置数据
/// </summary>
/// <param name="connectionToken">设备的连接标识</param>
/// <param name="setDataType">设置类型</param>
/// <param name="values">需要设置的数据</param>
/// <returns>是否设置成功</returns>
public async Task<bool> SetDatasAsync(string connectionToken, MachineSetDataType setDataType,
Dictionary<string, double> values)
{
BaseMachine machine = null;
lock (_machines)
{
machine = _machines.FirstOrDefault(p => p.ConnectionToken == machineToken);
machine = _machines.FirstOrDefault(p => p.ConnectionToken == connectionToken);
}
if (machine == null) return false;
return await machine.SetDatasAsync(setDataType, values);
}
/// <summary>
/// 启动TaskManager
/// </summary>
public void TaskStart()
{
TaskStop();
@@ -464,6 +511,9 @@ namespace ModBus.Net
GetCycle = TimeRestore.Restore;
}
/// <summary>
/// 停止TaskManager
/// </summary>
public void TaskStop()
{
lock (_machines)
@@ -484,6 +534,11 @@ namespace ModBus.Net
}
}
/// <summary>
/// 执行对具体设备的数据更新
/// </summary>
/// <param name="machine">设备的实例</param>
/// <returns></returns>
private async Task RunTask(BaseMachine machine)
{
try
@@ -504,10 +559,7 @@ namespace ModBus.Net
{
MoveMachineToLinked(machine.Id);
}
if (ReturnValues != null)
{
ReturnValues(new KeyValuePair<int, Dictionary<string,ReturnUnit>>(machine.Id, ans));
}
ReturnValues?.Invoke(new KeyValuePair<int, Dictionary<string,ReturnUnit>>(machine.Id, ans));
}
catch (Exception e)
{
@@ -515,10 +567,7 @@ namespace ModBus.Net
{
MoveMachineToUnlinked(machine.Id);
}
if (ReturnValues != null)
{
ReturnValues(new KeyValuePair<int, Dictionary<string,ReturnUnit>>(machine.Id, null));
}
ReturnValues?.Invoke(new KeyValuePair<int, Dictionary<string,ReturnUnit>>(machine.Id, null));
}
}
}

View File

@@ -25,7 +25,7 @@ namespace ModBus.Net
/// </summary>
public class TcpConnector : BaseConnector, IDisposable
{
public override string ConnectionToken { get { return _host; } }
public override string ConnectionToken => _host;
private readonly string _host;
@@ -60,13 +60,7 @@ namespace ModBus.Net
TimeoutTime = timeoutTime;
}
public override bool IsConnected
{
get
{
return _socketClient != null && _socketClient.Client != null && _socketClient.Connected;
}
}
public override bool IsConnected => _socketClient?.Client != null && _socketClient.Connected;
public void Dispose()
{

View File

@@ -33,10 +33,7 @@ namespace ModBus.Net
/// <summary>
/// 协议中的内容构造是否小端的,默认是小端构造协议。
/// </summary>
public static bool LittleEndian
{
get { return true; }
}
public static bool LittleEndian => true;
#region Factory
@@ -45,17 +42,7 @@ namespace ModBus.Net
/// <summary>
/// ValueHelper单例的实例
/// </summary>
public static ValueHelper Instance
{
get
{
if (_Instance == null)
{
_Instance = new ValueHelper();
}
return _Instance;
}
}
public static ValueHelper Instance => _Instance ?? (_Instance = new ValueHelper());
#endregion
@@ -705,22 +692,9 @@ namespace ModBus.Net
}
protected new bool LittleEndian
{
get { return false; }
}
protected new bool LittleEndian => false;
public new static BigEndianValueHelper Instance
{
get
{
if (_BigEndianInstance == null)
{
_BigEndianInstance = new BigEndianValueHelper();
}
return _BigEndianInstance;
}
}
public new static BigEndianValueHelper Instance => _BigEndianInstance ?? (_BigEndianInstance = new BigEndianValueHelper());
public override Byte[] GetBytes(short value)
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
</configuration>

View File

@@ -9,8 +9,9 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NA200H.UI.ConsoleApp</RootNamespace>
<AssemblyName>NA200H.UI.ConsoleApp</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>

View File

@@ -6,6 +6,8 @@ using System.Text;
using System.Threading.Tasks;
using ModBus.Net;
using System.Reflection;
using ModBus.Net.Modbus;
using ModBus.Net.Siemens;
namespace NA200H.UI.ConsoleApp
{
@@ -52,9 +54,9 @@ namespace NA200H.UI.ConsoleApp
}
Console.WriteLine();
Console.Read();
Console.Read();*/
Console.Read();
/*
//调用方法二:自动构造
//第一步:先生成一个输入结构体,然后向这个结构体中填写数据
AddressTranslator addressTranslator = new AddressTranslatorNA200H();
@@ -119,7 +121,8 @@ namespace NA200H.UI.ConsoleApp
Console.Read();
*/
/*BaseProtocal wrapper = new SiemensTcpProtocal(0x09, 0x1001, 0x1000, 0x0001, 0x0001, 0x03c0, ip);
/*
BaseProtocal wrapper = new SiemensTcpProtocal(0x09, 0x1001, 0x1000, 0x0001, 0x0001, 0x03c0, ip);
if (!wrapper.ProtocalLinker.IsConnected) return;
AddressTranslator addressTranslator = new AddressTranslatorSiemens();

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
</configuration>

View File

@@ -9,10 +9,11 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NA200H.UI.WPF</RootNamespace>
<AssemblyName>NA200H.UI.WPF</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>

View File

@@ -1,15 +1,15 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.34014
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将丢失。
// 重新生成代码,这些更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace NA200H.UI.WPF.Properties
{
namespace NA200H.UI.WPF.Properties {
using System;
/// <summary>
@@ -22,28 +22,23 @@ namespace NA200H.UI.WPF.Properties
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
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()
{
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NA200H.UI.WPF.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
@@ -52,18 +47,15 @@ namespace NA200H.UI.WPF.Properties
}
/// <summary>
/// 为所有资源查找重写当前线程的 CurrentUICulture 属性,
/// 方法是使用此强类型资源类
/// 使用此强类型资源类,为所有资源查找
/// 重写当前线程的 CurrentUICulture 属性
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}

View File

@@ -1,28 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34014
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace NA200H.UI.WPF.Properties
{
namespace NA200H.UI.WPF.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
public static Settings Default {
get {
return defaultInstance;
}
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
</configuration>

View File

@@ -30,13 +30,13 @@ namespace Siemens_S7_200.UI.WPF.TaskTest
//增加需要通信的PLC地址
List<AddressUnit> addressUnits = new List<AddressUnit>
{
new AddressUnit() {Id = 0, Area = "V", Address = 0, CommunicationTag = "D1", DataType = typeof (ushort), Zoom = 1},
new AddressUnit() {Id = 1, Area = "V", Address = 2, CommunicationTag = "D2", DataType = typeof (float), Zoom = 1}
new AddressUnit() {Id = 0, Area = "V", Address = 1, CommunicationTag = "D1", DataType = typeof (ushort), Zoom = 1},
new AddressUnit() {Id = 1, Area = "V", Address = 3, CommunicationTag = "D2", DataType = typeof (float), Zoom = 1}
};
//初始化任务管理器
TaskManager task = new TaskManager(300, true);
//向任务管理器中添加设备
task.AddMachine(new SiemensMachine(SiemensType.Tcp, "192.168.3.191",SiemensMachineModel.S7_200, addressUnits,
task.AddMachine(new SiemensMachine(SiemensType.Tcp, "192.168.3.11",SiemensMachineModel.S7_300, addressUnits,
true));
//增加值返回时的处理函数
task.ReturnValues += (returnValues) =>
@@ -45,12 +45,12 @@ namespace Siemens_S7_200.UI.WPF.TaskTest
value = new List<string>();
if (returnValues.Value != null)
{
value = from val in returnValues.Value select val.Key + val.Value;
value = from val in returnValues.Value select val.Key + " " + val.Value.PlcValue;
siemensItems.Dispatcher.Invoke(() => siemensItems.ItemsSource = value);
}
else
{
Console.WriteLine(String.Format("ip {0} not return value", returnValues.Key));
Console.WriteLine($"ip {returnValues.Key} not return value");
}
};
//启动任务

View File

@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Siemens_S7_200.UI.WPF.TaskTest</RootNamespace>
<AssemblyName>Siemens_S7_200.UI.WPF.TaskTest</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>

View File

@@ -19,7 +19,7 @@ Table of Content:
* Siemens Tcp protocal (acturally it is the same as Profinet)
* All communications can be asyncronized.
* A task manager that you can easily manage multiple connections.
* .net 4.5 and Visual Studio 2013 support (In the future, it will be upgraded to .net 4.6 and Visual Studio 2015)
* .net framework 4.6 and Visual Studio 2015 support.
##<a name="usage"></a> Usage