整理文件

This commit is contained in:
Kimdiego2098
2023-11-18 23:02:28 +08:00
parent bfe48ae9d2
commit 76fd08eade
901 changed files with 130851 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
<Project>
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
<Version>4.0.0.0</Version>
<LangVersion>latest</LangVersion>
<Authors>Diego</Authors>
<Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright>
<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl>
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,16 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
global using System;
global using ThingsGateway.Components;

View File

@@ -0,0 +1,39 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Photino.Blazor;
namespace ThingsGateway.Foundation.Demo;
internal class Program
{
[STAThread]
private static void Main(string[] args)
{
System.IO.Directory.SetCurrentDirectory(AppContext.BaseDirectory);
var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args);
Serve.RunNative();
appBuilder.RootComponents.Add<App>("#app");
appBuilder.Services.ThingsGatewayComponentsConfigureServices();
var app = appBuilder.Build();
app.MainWindow.SetTitle("ThingsGateway.Foundation.Demo");
app.MainWindow.SetIconFile("wwwroot/favicon.ico");
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
{
};
app.Run();
}
}

View File

@@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="favicon.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="favicon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Photino.Blazor" Version="2.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="wwwroot\favicon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\favicon.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<title>ThingsGateway.Foundation.Demo</title>
<base href="/" />
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link href="_content/Masa.Blazor/css/masa-blazor.min.css" rel="stylesheet" />
<link href="_content/ThingsGateway.Components/css/materialdesign/v7.1.96/css/materialdesignicons.min.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/css/material/icons.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/css/fontawesome/v6.4.0/css/all.min.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/style/custom.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/prism/prism-material-dark-for-masa.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/prism/prism-line-highlight.min.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<div id="blazor-error-ui">
<span>
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
</span>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webview.js" autostart="true"></script>
<script src="_content/ThingsGateway.Components/prism/prism.min.js"></script>
<script src="_content/BlazorComponent/js/blazor-component.js"></script>
</body>
</html>

View File

@@ -0,0 +1,26 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>

View File

@@ -0,0 +1,144 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Microsoft.AspNetCore.Components;
namespace ThingsGateway.Foundation.Demo;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
/// <summary>
/// 调试UI
/// </summary>
public abstract class DriverDebugUIBase : ComponentBase, IDisposable
{
/// <summary>
/// 日志缓存
/// </summary>
public ConcurrentLinkedList<(LogLevel level, string message)> Messages = new();
private PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(1));
/// <inheritdoc/>
~DriverDebugUIBase()
{
this.SafeDispose();
}
/// <summary>
/// 变量地址
/// </summary>
public virtual string Address { get; set; } = "40001";
/// <summary>
/// <inheritdoc/>
/// </summary>
[Inject]
public InitTimezone InitTimezone { get; set; }
/// <summary>
/// 长度
/// </summary>
public virtual int Length { get; set; } = 1;
/// <summary>
/// 默认读写设备
/// </summary>
public virtual IReadWrite Plc { get; set; }
/// <summary>
/// 写入值
/// </summary>
public virtual string WriteValue { get; set; }
/// <summary>
/// 数据类型
/// </summary>
protected virtual DataTypeEnum DataTypeEnum { get; set; } = DataTypeEnum.Int16;
/// <inheritdoc/>
public virtual void Dispose()
{
_periodicTimer?.Dispose();
}
/// <inheritdoc/>
public void LogOut(ThingsGateway.Foundation.Core.LogLevel logLevel, object source, string message, Exception exception)
{
Messages.Add(((LogLevel)logLevel,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {message} {exception}"));
if (Messages.Count > 2500)
{
Messages.Clear();
}
}
/// <inheritdoc/>
public virtual async Task ReadAsync()
{
try
{
var data = await Plc.ReadAsync(Address, Length, DataTypeEnum);
if (data.IsSuccess)
{
Messages.Add((LogLevel.Information,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 对应类型值:{Environment.NewLine}{data.Content.ToJsonString(true)} "));
}
else
{
Messages.Add((LogLevel.Warning,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}"));
}
}
catch (Exception ex)
{
Messages.Add((LogLevel.Error,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex}"));
}
}
/// <inheritdoc/>
public virtual async Task WriteAsync()
{
try
{
var data = await Plc.WriteAsync(Address, WriteValue, Length, DataTypeEnum);
if (data.IsSuccess)
{
Messages.Add((LogLevel.Information,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}"));
}
else
{
Messages.Add((LogLevel.Warning,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}"));
}
}
catch (Exception ex)
{
Messages.Add((LogLevel.Error,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex}"));
}
}
/// <inheritdoc/>
protected override void OnInitialized()
{
_ = RunTimerAsync();
base.OnInitialized();
}
private async Task RunTimerAsync()
{
while (await _periodicTimer.WaitForNextTickAsync())
{
await InvokeAsync(StateHasChanged);
}
}
}

View File

@@ -0,0 +1,205 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
@inherits DriverDebugUIBase
<MCard Elevation="1" Rounded="false" Class=" pa-2" Style="width:100%">
<MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters>
<MCol Md="5">
<MTabs @bind-Value="tab" Class="ma-2">
<MTab Value=1> 读写测试 </MTab>
<MTab Value=2> 特殊功能 </MTab>
<MTab Value=3> 代码示例 </MTab>
</MTabs>
<MTabsItems Value="tab">
<MTabItem Value="1">
@if (tab == 1)
{
@if (ReadWriteContent == null)
{
<div class="my-1 py-1">
<MTooltip Bottom Context="tip">
<ActivatorContent>
<MTextarea Class="mx-1 my-1" Label="变量地址" @attributes="@tip.Attrs" Dense Outlined HideDetails="@("auto")" @bind-Value=@Address />
</ActivatorContent>
<ChildContent>
<span style="white-space: pre-wrap;">@Plc?.GetAddressDescription()</span>
</ChildContent>
</MTooltip>
<MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters>
<MTextField Class="mx-1 my-1" Style="max-width:200px" Label="读取长度" Dense Outlined HideDetails="@("auto")" @bind-Value=@Length />
<MSelect Class="mx-1 my-1" Style="max-width:200px" @bind-Value="DataTypeEnum" Outlined Label="数据类型"
Items=@(typeof(DataTypeEnum).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataTypeEnum)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
</MRow>
<MButton Class="mx-1 my-1" Color="primary" OnClick="ReadAsync">
读取
</MButton>
<MTextarea Class="mx-1 mt-3 my-1" Label="值" Dense Outlined HideDetails="@("auto")" @bind-Value=@WriteValue />
<MButton Class="mx-1 my-1" Color="primary" OnClick="WriteAsync">
写入
</MButton>
</div>
}
else
{
@ReadWriteContent
}
}
</MTabItem>
<MTabItem Value="2">
@if (tab == 2)
{
@if (ShowDefaultOtherContent)
{
<MSubheader>
连读打包
</MSubheader>
<MContainer>
@foreach (var item in DeviceVariableRunTimes)
{
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="min-width:100px" Label=@(item.Description(x => x.Address)) Dense HideDetails="@("auto")" @bind-Value=@item.Address></MTextField>
<MSelect Class="mx-1 my-1" Style="max-width:120px" @bind-Value="item.DataTypeEnum" Outlined Label=@(item.Description(x => x.DataTypeEnum))
Items=@(typeof(DataTypeEnum).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataTypeEnum)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(item.Description(x => x.IntervalTime)) Dense HideDetails="@("auto")" @bind-Value=@item.IntervalTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=实时值 Readonly ClearIcon="" Dense HideDetails="@("auto")" Value=item.Value?.ToJsonString()></MTextField>
</MRow>
}
<MRow Dense>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label="打包长度" Dense HideDetails="@("auto")" @bind-Value=@MaxPack></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="MulReadAsync">
读取
</MButton>
</MRow>
</MContainer>
}
@if (OtherContent != null)
{
<MSheet Style="height:100%;overflow-y:auto">
@OtherContent
</MSheet>
}
}
</MTabItem>
<MTabItem Value="3">
@if (tab == 3)
{
@if (CodeContent != null)
@CodeContent
else
{
<MRow Align="AlignTypes.Center">
<MContainer>
<MItemGroup @bind-Value="_selected" Class="shrink mr-6" Mandatory>
@{
int index = 0;
}
<MRow>
@foreach (var item in Sections)
{
<MItem Value="@(index++)">
<div>
<MButton IsActive="@context.Active" Icon OnClick="@context.Toggle">
<MIcon>mdi-record</MIcon>
</MButton>
</div>
</MItem>
}
</MRow>
</MItemGroup>
</MContainer>
<MCol>
<MWindow Value="_selected" Vertical Class="elevation-1 grey lighten-5 rounded-b" Style=@($"height:450px;overflow:auto")>
@{
int index = 0;
}
@foreach (var item in Sections)
{
<MWindowItem Value="@(index++)">
<AppCode RoundedTop0 Code="@item.Code" Language="@item.Language" />
</MWindowItem>
}
</MWindow>
</MCol>
</MRow>
}
}
</MTabItem>
</MTabsItems>
</MCol>
<MCol Md="7">
<MCard Style="overflow-y:auto;width:100%" Elevation="0" Flat Class="ml-4">
<ConsoleTxt Messages="Messages" Height=500></ConsoleTxt>
</MCard>
</MCol>
</MRow>
</MCard>
@code {
StringNumber tab;
}

View File

@@ -0,0 +1,238 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using BlazorComponent;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class DriverDebugUIPage : DriverDebugUIBase
{
/// <summary>
/// DeviceVariableRunTimes
/// </summary>
public List<DeviceVariableRunTime> DeviceVariableRunTimes;
/// <summary>
/// MaxPack
/// </summary>
public int MaxPack = 100;
private StringNumber _selected = 0;
/// <inheritdoc/>
~DriverDebugUIPage()
{
this.SafeDispose();
}
/// <summary>
/// 自定义模板
/// </summary>
[Parameter]
public RenderFragment CodeContent { get; set; }
/// <summary>
/// 自定义模板
/// </summary>
[Parameter]
public RenderFragment OtherContent { get; set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public override IReadWrite Plc { get; set; }
/// <summary>
/// 自定义模板
/// </summary>
[Parameter]
public RenderFragment ReadWriteContent { get; set; }
/// <summary>
/// Sections
/// </summary>
[Parameter]
public List<(string Code, string Language)> Sections { get; set; } = new();
/// <summary>
/// ShowDefaultOtherContent
/// </summary>
[Parameter]
public bool ShowDefaultOtherContent { get; set; } = true;
/// <inheritdoc/>
public override void Dispose()
{
Plc?.SafeDispose();
base.Dispose();
}
/// <summary>
/// MulReadAsync
/// </summary>
/// <returns></returns>
public async Task MulReadAsync()
{
var deviceVariableSourceReads = Plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(DeviceVariableRunTimes, MaxPack, 1000);
foreach (var item in deviceVariableSourceReads)
{
var result = await Plc.ReadAsync(item.Address, item.Length);
if (result.IsSuccess)
{
try
{
item.DeviceVariableRunTimes.PraseStructContent(Plc, result.Content);
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + result.Content.ToHexString(' ')));
}
catch (Exception ex)
{
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex));
}
}
else
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);
}
/// <inheritdoc/>
protected override void OnInitialized()
{
DeviceVariableRunTimes = new()
{
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40001",
IntervalTime=1000,
},
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40011",
IntervalTime=1000,
},
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40031",
IntervalTime=1000,
},
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40101",
IntervalTime=1000,
},
};
Sections.Add((
"""
/// <inheritdoc/>
public class DeviceVariableSourceRead : IDeviceVariableSourceRead<DeviceVariableRunTime>
{
/// <inheritdoc/>
public TimerTick TimerTick { get; set; }
/// <inheritdoc/>
public string Address { get; set; }
/// <inheritdoc/>
public int Length { get; set; }
/// <inheritdoc/>
public List<DeviceVariableRunTime> DeviceVariableRunTimes { get; set; } = new List<DeviceVariableRunTime>();
}
/// <inheritdoc/>
public class DeviceVariableRunTime : IDeviceVariableRunTime
{
/// <inheritdoc/>
[Description("读取间隔")]
public int IntervalTime { get; set; }
/// <inheritdoc/>
[Description("变量地址")]
public string Address { get; set; }
/// <inheritdoc/>
public int Index { get; set; }
/// <inheritdoc/>
public IThingsGatewayBitConverter ThingsGatewayBitConverter { get; set; }
/// <inheritdoc/>
[Description("数据类型")]
public DataTypeEnum DataTypeEnum { get; set; }
/// <inheritdoc/>
[Description("实时值")]
public object Value { get; set; }
/// <inheritdoc/>
public OperResult SetValue(object value)
{
Value = value;
return OperResult.CreateSuccessResult();
}
}
public List<DeviceVariableRunTime> DeviceVariableRunTimes;
private static async Task ModbusClientAsync(IReadWrite plc)
{
DeviceVariableRunTimes = new()
{
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40001",
IntervalTime=1000,
},
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40011",
IntervalTime=1000,
},
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40031",
IntervalTime=1000,
},
new DeviceVariableRunTime()
{
DataTypeEnum=DataTypeEnum.Int16,
Address="40101",
IntervalTime=1000,
},
};
#region
var deviceVariableSourceReads = Plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(DeviceVariableRunTimes, MaxPack);
foreach (var item in deviceVariableSourceReads)
{
var result = await Plc.ReadAsync(item.Address, item.Length);
if (result.IsSuccess)
{
item.DeviceVariableRunTimes.PraseStructContent(result.Content);
}
}
#endregion
}
""", "csharp"));
base.OnInitialized();
}
}

View File

@@ -0,0 +1,47 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using Masa.Blazor
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">通道配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
<MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(_serialProperty.Description(x => x.PortName)) Dense HideDetails="@("auto")" @bind-Value=@_serialProperty.PortName />
<MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(_serialProperty.Description(x => x.BaudRate)) Dense HideDetails="@("auto")" @bind-Value=@_serialProperty.BaudRate />
<MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(_serialProperty.Description(x => x.DataBits)) Dense HideDetails="@("auto")" @bind-Value=@_serialProperty.DataBits />
<MSelect Class="ma-1 " Style="max-width:200px" Outlined @bind-Value="_serialProperty.Parity" Label="@(_serialProperty.Description(x => x.Parity))"
Items=@(typeof(Parity).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(Parity)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MSelect Class="ma-1 " Style="max-width:200px" Outlined @bind-Value="_serialProperty.StopBits" Label="@(_serialProperty.Description(x => x.StopBits))"
Items=@(typeof(StopBits).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(StopBits)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
连接
</MButton>
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
断开
</MButton>
</MRow>
</MCard>

View File

@@ -0,0 +1,104 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class SerialSessionPage : IDisposable
{
/// <summary>
/// 日志输出
/// </summary>
public Action<LogLevel, object, string, Exception> LogAction;
private readonly SerialProperty _serialProperty = new();
private TouchSocketConfig _config;
private SerialSession _serialSession { get; set; } = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
public void Dispose()
{
_serialSession.SafeDispose();
}
/// <summary>
/// 获取对象
/// </summary>
/// <returns></returns>
public SerialSession GetSerialSession()
{
_config ??= new TouchSocketConfig();
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetSerialProperty(_serialProperty);
//载入配置
_serialSession.Setup(_config);
return _serialSession;
}
internal void StateHasChangedAsync()
{
StateHasChanged();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_serialSession.Setup(_config);
}
base.OnAfterRender(firstRender);
}
/// <inheritdoc/>
protected override void OnInitialized()
{
_config ??= new TouchSocketConfig();
base.OnInitialized();
}
private async Task ConnectAsync()
{
try
{
_serialSession.Close();
await GetSerialSession().ConnectAsync();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void DisConnect()
{
try
{
_serialSession.Close();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
}

View File

@@ -0,0 +1,34 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">通道配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
<MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@_ip />
<MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@_port />
<MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
连接
</MButton>
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
断开
</MButton>
</MRow>
</MCard>

View File

@@ -0,0 +1,116 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class TcpClientPage : IDisposable
{
/// <summary>
/// 日志输出
/// </summary>
public Action<LogLevel, object, string, Exception> LogAction;
private TouchSocketConfig _config;
/// <summary>
/// IP
/// </summary>
private string _ip = "127.0.0.1";
/// <summary>
/// Port
/// </summary>
public int _port { get; set; } = 502;
private TcpClient _tcpClient { get; set; } = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
public void Dispose()
{
_tcpClient.SafeDispose();
}
/// <summary>
/// 获取对象
/// </summary>
/// <returns></returns>
public TcpClient GetTcpClient()
{
_config ??= new TouchSocketConfig();
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetRemoteIPHost(new IPHost(_ip + ":" + _port));
//载入配置
_tcpClient.Setup(_config);
return _tcpClient;
}
internal void StateHasChangedAsync()
{
StateHasChanged();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetRemoteIPHost(new IPHost(_ip + ":" + _port));
_tcpClient.Setup(_config);
}
base.OnAfterRender(firstRender);
}
/// <inheritdoc/>
protected override void OnInitialized()
{
_config ??= new TouchSocketConfig();
base.OnInitialized();
}
private async Task ConnectAsync()
{
try
{
_tcpClient.Close();
await GetTcpClient().ConnectAsync();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void DisConnect()
{
try
{
_tcpClient.Close();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
}

View File

@@ -0,0 +1,38 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">通道配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
<MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@_ip />
<MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@_port />
<MButton Class="ma-1" OnClick=@Connect Color="primary">
启动
</MButton>
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
停止
</MButton>
</MRow>
</MCard>

View File

@@ -0,0 +1,111 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class TcpServerPage : IDisposable
{
/// <summary>
/// 日志输出
/// </summary>
public Action<LogLevel, object, string, Exception> LogAction;
private TouchSocketConfig _config;
private string _ip = "127.0.0.1";
private int _port = 502;
private TcpService _tcpServer { get; set; } = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
public void Dispose()
{
_tcpServer.SafeDispose();
}
/// <summary>
/// 获取对象
/// </summary>
/// <returns></returns>
public TcpService GetTcpServer()
{
_config ??= new TouchSocketConfig();
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetListenIPHosts(new IPHost[] { new IPHost(_ip + ":" + _port) });
//载入配置
_tcpServer.Setup(_config);
return _tcpServer;
}
internal void StateHasChangedAsync()
{
StateHasChanged();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetListenIPHosts(new IPHost[] { new IPHost(_ip + ":" + _port) });
_tcpServer.Setup(_config);
}
base.OnAfterRender(firstRender);
}
/// <inheritdoc/>
protected override void OnInitialized()
{
_config ??= new TouchSocketConfig();
base.OnInitialized();
}
private void Connect()
{
try
{
_tcpServer.Stop();
GetTcpServer().Start();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void DisConnect()
{
try
{
_tcpServer.Stop();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
}

View File

@@ -0,0 +1,37 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">通道配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
<MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@_ip />
<MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@_port />
<MButton Class="ma-1" OnClick=Connect Color="primary">
连接
</MButton>
<MButton Class="ma-1" OnClick=DisConnect Color="red">
断开
</MButton>
</MRow>
</MCard>

View File

@@ -0,0 +1,118 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class UdpSessionPage : IDisposable
{
/// <summary>
/// IP
/// </summary>
public string _ip = "127.0.0.1";
/// <summary>
/// Port
/// </summary>
public int _port = 502;
/// <summary>
/// 日志输出
/// </summary>
public Action<LogLevel, object, string, Exception> LogAction;
private TouchSocketConfig _config;
private UdpSession _udpSession { get; set; } = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
public void Dispose()
{
_udpSession.SafeDispose();
}
/// <summary>
/// 获取对象
/// </summary>
/// <returns></returns>
public UdpSession GetUdpSession()
{
_config ??= new TouchSocketConfig();
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetRemoteIPHost(new IPHost(_ip + ":" + _port));
_config.SetBindIPHost(new IPHost(0));
//载入配置
_udpSession.Setup(_config);
return _udpSession;
}
internal void StateHasChangedAsync()
{
StateHasChanged();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
_config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
_config.SetRemoteIPHost(new IPHost(_ip + ":" + _port));
_config.SetBindIPHost(new IPHost(0));
_udpSession.Setup(_config);
}
base.OnAfterRender(firstRender);
}
/// <inheritdoc/>
protected override void OnInitialized()
{
_config ??= new TouchSocketConfig();
base.OnInitialized();
}
private void Connect()
{
try
{
_udpSession.Stop();
GetUdpSession().Start();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void DisConnect()
{
try
{
_udpSession.Stop();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
}

View File

@@ -0,0 +1,48 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public class DeviceVariableRunTime : IDeviceVariableRunTime
{
/// <inheritdoc/>
[Description("读取间隔")]
public int? IntervalTime { get; set; }
/// <inheritdoc/>
[Description("变量地址")]
public string Address { get; set; }
/// <inheritdoc/>
public int Index { get; set; }
/// <inheritdoc/>
public IThingsGatewayBitConverter ThingsGatewayBitConverter { get; set; }
/// <inheritdoc/>
[Description("数据类型")]
public DataTypeEnum DataTypeEnum { get; set; }
/// <inheritdoc/>
[Description("实时值")]
public object Value { get; set; }
public bool IsOnline { get; set; }
public string LastErrorMessage { get; set; }
/// <inheritdoc/>
public OperResult SetValue(object value, DateTime dateTime = default, string lastErrorMessage = null)
{
Value = value;
return OperResult.CreateSuccessResult();
}
}

View File

@@ -0,0 +1,28 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public class DeviceVariableSourceRead : IDeviceVariableSourceRead<IDeviceVariableRunTime>
{
/// <inheritdoc/>
public TimerTick IntervalTimeTick { get; set; }
/// <inheritdoc/>
public string Address { get; set; }
/// <inheritdoc/>
public int Length { get; set; }
/// <inheritdoc/>
public List<IDeviceVariableRunTime> DeviceVariableRunTimes { get; set; } = new List<IDeviceVariableRunTime>();
}

View File

@@ -0,0 +1,21 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
global using System;
global using System.Threading;
global using System.Threading.Tasks;
global using ThingsGateway.Components;
global using ThingsGateway.Foundation.Core;
global using ThingsGateway.Foundation.Serial;
global using ThingsGateway.Foundation.Sockets;

View File

@@ -0,0 +1,36 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/"
@layout BaseLayout
@inject NavigationManager NavigationManager
@namespace ThingsGateway.Foundation.Demo
@using Microsoft.AspNetCore.Authorization;
@code {
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
/// <returns></returns>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
NavigationManager.NavigateTo("index");
}
await base.OnAfterRenderAsync(firstRender);
}
}

View File

@@ -0,0 +1,218 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/DLT645_2007"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<SerialSessionPage @ref=_serialSessionPage></SerialSessionPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.OperCode)) Dense HideDetails="@("auto")" @bind-Value=@_plc.OperCode></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Password)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Password></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.EnableFEHead)) Dense HideDetails="@("auto")" @bind-Value=@_plc.EnableFEHead></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections" ShowDefaultOtherContent=false>
<OtherContent>
<MSubheader>
广播校时
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<PDateDigitalClockPicker @bind-Value="dateTime" TimeFormat="TimeFormat.Hr24" ViewType="DateTimePickerViewType.Auto" Context="dateContext">
<ActivatorContent>
<MTextField @bind-Value="dateTime" Style="max-width:200px;" Class="ma-1" Outlined HideDetails=@("auto") Dense Clearable Readonly @attributes="@dateContext.Attrs">
</MTextField>
</ActivatorContent>
</PDateDigitalClockPicker>
<MButton Class="ma-1" Color="primary" OnClick="()=>_plc.BroadcastTime(dateTime)">
校时
</MButton>
</MRow>
</MContainer>
<MSubheader>
冻结
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<PDateDigitalClockPicker @bind-Value="dateTime" TimeFormat="TimeFormat.Hr24" ViewType="DateTimePickerViewType.Auto" Context="dateContext">
<ActivatorContent>
<MTextField @bind-Value="dateTime" Style="max-width:200px;" Class="ma-1" Outlined HideDetails=@("auto") Dense Clearable Readonly @attributes="@dateContext.Attrs">
</MTextField>
</ActivatorContent>
</PDateDigitalClockPicker>
<MButton Class="ma-1" Color="primary" OnClick="()=>_plc.FreezeAsync(dateTime)">
冻结
</MButton>
</MRow>
</MContainer>
<MSubheader>
读取通信地址
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MButton Class="ma-1" Color="primary" OnClick="ReadDeviceStationAsync">
读取通信地址
</MButton>
</MRow>
</MContainer>
<MSubheader>
修改波特率
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=波特率 Clearable Dense HideDetails="@("auto")" @bind-Value=baudRate></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="WriteBaudRateAsync">
修改波特率
</MButton>
</MRow>
</MContainer>
<MSubheader>
更新通信地址
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=通信地址 Clearable Dense HideDetails="@("auto")" @bind-Value=station></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="WriteDeviceStationAsync">
更新通信地址
</MButton>
</MRow>
</MContainer>
<MSubheader>
修改密码
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=级别(0-9) Clearable Dense HideDetails="@("auto")" @bind-Value=level></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=旧密码 Clearable Dense HideDetails="@("auto")" @bind-Value=oldPassword></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=新密码 Clearable Dense HideDetails="@("auto")" @bind-Value=newPassword></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="WritePasswordAsync">
修改密码
</MButton>
</MRow>
</MContainer>
</OtherContent>
</DriverDebugUIPage>
@code {
private byte level;
private string oldPassword;
private string newPassword;
private async Task WritePasswordAsync()
{
var result = await _plc.WritePasswordAsync(level, oldPassword, newPassword);
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private string station;
private async Task WriteDeviceStationAsync()
{
var result = await _plc.WriteDeviceStationAsync(station);
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private int baudRate;
private async Task WriteBaudRateAsync()
{
var result = await _plc.WriteBaudRateAsync(baudRate);
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private async Task ReadDeviceStationAsync()
{
var result = await _plc.ReadDeviceStationAsync();
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Content));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private DateTime dateTime;
}
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,88 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class DLT645_2007DebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private SerialSessionPage _serialSessionPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007 _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetSerialProperty(new SerialProperty() //串口链路才需要
{
PortName = "COM1"
});
var serialSession = new SerialSession();//链路对象
serialSession.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
DLT645_2007 plc = new(serialSession)//传入链路
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var result = await plc.ReadStringAsync("00000000", 1);
#endregion
}
""", "csharp"));
if (_serialSessionPage != null)
_serialSessionPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007(_serialSessionPage.GetSerialSession());
_driverDebugUIPage.Plc = _plc;
//初始化
_driverDebugUIPage.Address = "02010100";
_driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.Address = "02010100");
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,217 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/DLT645_2007OverTcp"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<TcpClientPage @ref=_tcpClientPage></TcpClientPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.OperCode)) Dense HideDetails="@("auto")" @bind-Value=@_plc.OperCode></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Password)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Password></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.EnableFEHead)) Dense HideDetails="@("auto")" @bind-Value=@_plc.EnableFEHead></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections" ShowDefaultOtherContent=false>
<OtherContent>
<MSubheader>
广播校时
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<PDateDigitalClockPicker @bind-Value="dateTime" TimeFormat="TimeFormat.Hr24" ViewType="DateTimePickerViewType.Auto" Context="dateContext">
<ActivatorContent>
<MTextField @bind-Value="dateTime" Style="max-width:200px;" Class="ma-1" Outlined HideDetails=@("auto") Dense Clearable Readonly @attributes="@dateContext.Attrs">
</MTextField>
</ActivatorContent>
</PDateDigitalClockPicker>
<MButton Class="ma-1" Color="primary" OnClick="()=>_plc.BroadcastTime(dateTime)">
校时
</MButton>
</MRow>
</MContainer>
<MSubheader>
冻结
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<PDateDigitalClockPicker @bind-Value="dateTime" TimeFormat="TimeFormat.Hr24" ViewType="DateTimePickerViewType.Auto" Context="dateContext">
<ActivatorContent>
<MTextField @bind-Value="dateTime" Style="max-width:200px;" Class="ma-1" Outlined HideDetails=@("auto") Dense Clearable Readonly @attributes="@dateContext.Attrs">
</MTextField>
</ActivatorContent>
</PDateDigitalClockPicker>
<MButton Class="ma-1" Color="primary" OnClick="()=>_plc.FreezeAsync(dateTime)">
冻结
</MButton>
</MRow>
</MContainer>
<MSubheader>
读取通信地址
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MButton Class="ma-1" Color="primary" OnClick="ReadDeviceStationAsync">
读取通信地址
</MButton>
</MRow>
</MContainer>
<MSubheader>
修改波特率
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=波特率 Clearable Dense HideDetails="@("auto")" @bind-Value=baudRate></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="WriteBaudRateAsync">
修改波特率
</MButton>
</MRow>
</MContainer>
<MSubheader>
更新通信地址
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=通信地址 Clearable Dense HideDetails="@("auto")" @bind-Value=station></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="WriteDeviceStationAsync">
更新通信地址
</MButton>
</MRow>
</MContainer>
<MSubheader>
修改密码
</MSubheader>
<MContainer>
<MRow Dense Align="AlignTypes.Center">
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=级别(0-9) Clearable Dense HideDetails="@("auto")" @bind-Value=level></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=旧密码 Clearable Dense HideDetails="@("auto")" @bind-Value=oldPassword></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:200px" Label=新密码 Clearable Dense HideDetails="@("auto")" @bind-Value=newPassword></MTextField>
<MButton Class="ma-1" Color="primary" OnClick="WritePasswordAsync">
修改密码
</MButton>
</MRow>
</MContainer>
</OtherContent>
</DriverDebugUIPage>
@code {
private byte level;
private string oldPassword;
private string newPassword;
private async Task WritePasswordAsync()
{
var result = await _plc.WritePasswordAsync(level, oldPassword, newPassword);
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private string station;
private async Task WriteDeviceStationAsync()
{
var result = await _plc.WriteDeviceStationAsync(station);
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private int baudRate;
private async Task WriteBaudRateAsync()
{
var result = await _plc.WriteBaudRateAsync(baudRate);
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private async Task ReadDeviceStationAsync()
{
var result = await _plc.ReadDeviceStationAsync();
if (result.IsSuccess)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Content));
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(_driverDebugUIPage.InitTimezone.TimezoneOffset) + " - " + result.Message));
}
}
private DateTime dateTime;
}
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,87 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class DLT645_2007OverTcpDebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private TcpClientPage _tcpClientPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var tcpClient1 = new TcpClient();//链路对象
tcpClient1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
DLT645_2007OverTcp plc = new(tcpClient1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var result = await plc.ReadStringAsync("00000000", 1);
#endregion
}
""", "csharp"));
if (_tcpClientPage != null)
_tcpClientPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp(_tcpClientPage.GetTcpClient());
_driverDebugUIPage.Plc = _plc;
//初始化
_driverDebugUIPage.Address = "02010100";
_driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.Address = "02010100");
_tcpClientPage._port = 5000;
_tcpClientPage.StateHasChangedAsync();
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,57 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/index"
<div class="ml-2">
<div class="my-6 ">
<MLabel Class="text-h3" Color="primary">ThingsGateway</MLabel>
</div>
<div>
<strong class="text--lighten-1 text-h5 my-1">文档</strong>
</div>
<div class="my-2 ml-4">
<PCopyableText>
https://diego2098.gitee.io/thingsgateway-docs/
</PCopyableText>
</div>
<div>
<strong class="text--lighten-1 text-h5 my-1">协议</strong>
</div>
<div class="my-2 ml-4">
<PCopyableText Text="https://gitee.com/diego2098/ThingsGateway/blob/master/LICENSE.zh">
Apache-2.0开源协议
</PCopyableText>
</div>
<div>
<strong class="text--lighten-1 text-h5 my-1">赞助</strong>
</div>
<div class="my-2 ml-4">
<PCopyableText Text="https://diego2098.gitee.io/thingsgateway-docs/docs/donate">
ThingsGateway赞助途径
</PCopyableText>
</div>
<div>
<strong class="text--lighten-1 text-h5 my-1">社区</strong>
</div>
<div class="my-2 ml-4">
<PCopyableText Text="605534569">
QQ群605534569
</PCopyableText>
</div>
</div>

View File

@@ -0,0 +1,56 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusRtu"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<SerialSessionPage @ref=_serialSessionPage></SerialSessionPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>

View File

@@ -0,0 +1,86 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class ModbusRtuDebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private SerialSessionPage _serialSessionPage;
private readonly List<(string Code, string Language)> _sections = new();
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetSerialProperty(new SerialProperty() //串口链路才需要
{
PortName = "COM1"
});
var serialSession = new SerialSession();//链路对象
serialSession.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusRtu plc = new(serialSession)//传入链路
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_serialSessionPage != null)
_serialSessionPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu(_serialSessionPage.GetSerialSession());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,56 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusRtuOverTcp"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<TcpClientPage @ref=_tcpClientPage></TcpClientPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>

View File

@@ -0,0 +1,84 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class ModbusRtuOverTcpDebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private TcpClientPage _tcpClientPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp _plc;
private readonly List<(string Code, string Language)> _sections = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var tcpClient1 = new TcpClient();//链路对象
tcpClient1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusRtuOverTcp plc = new(tcpClient1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_tcpClientPage != null)
_tcpClientPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp(_tcpClientPage.GetTcpClient());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,59 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusRtuOverUdp"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<UdpSessionPage @ref=_udpSessionPage></UdpSessionPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.Crc16CheckEnable)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,80 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class ModbusRtuOverUdpDebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private UdpSessionPage _udpSessionPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var udpSession1 = new UdpSession();//链路对象
udpSession1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusRtuOverUdp plc = new(udpSession1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_udpSessionPage != null)
_udpSessionPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp(_udpSessionPage.GetUdpSession());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,59 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusSerialServer"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<SerialSessionPage @ref=_serialSessionPage></SerialSessionPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.MulStation)) Dense HideDetails="@("auto")" @bind-Value=@_plc.MulStation></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,84 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class ModbusSerialServerDebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private SerialSessionPage _serialSessionPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusSerialServer _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetSerialProperty(new SerialProperty() //串口链路才需要
{
PortName = "COM1"
});
var serialSession = new SerialSession();//链路对象
serialSession.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusSerialServer plc = new(serialSession)//传入链路
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_serialSessionPage != null)
_serialSessionPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusSerialServer(_serialSessionPage.GetSerialSession());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,59 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusTcp"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<TcpClientPage @ref=_tcpClientPage></TcpClientPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,81 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class ModbusTcpDebugPage
{
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp _plc;
/// <summary>
/// SerialSessionPage
/// </summary>
private TcpClientPage _tcpClientPage;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var tcpClient1 = new TcpClient();//链路对象
tcpClient1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusTcp plc = new(tcpClient1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
IsCheckMessageId = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_tcpClientPage != null)
_tcpClientPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp(_tcpClientPage.GetTcpClient());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,59 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusTcpDtu"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<TcpServerPage @ref=_tcpServerPage></TcpServerPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,81 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// ModbusTcpDtuDebugPage
/// </summary>
public partial class ModbusTcpDtuDebugPage
{
/// <summary>
/// TcpServerPage
/// </summary>
private TcpServerPage _tcpServerPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDtu _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var tcpClient1 = new TcpClient();//链路对象
tcpClient1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusTcpDtu plc = new(tcpClient1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
IsCheckMessageId = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_tcpServerPage != null)
_tcpServerPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDtu(_tcpServerPage.GetTcpServer());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,59 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusTcpServer"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<TcpServerPage @ref=_tcpServerPage></TcpServerPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.MulStation)) Dense HideDetails="@("auto")" @bind-Value=@_plc.MulStation></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,81 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// ModbusTcpServerDebugPage
/// </summary>
public partial class ModbusTcpServerDebugPage
{
/// <summary>
/// TcpServerPage
/// </summary>
private TcpServerPage _tcpServerPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpServer _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var tcpClient1 = new TcpClient();//链路对象
tcpClient1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusTcpServer plc = new(tcpClient1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
IsCheckMessageId = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_tcpServerPage != null)
_tcpServerPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpServer(_tcpServerPage.GetTcpServer());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,59 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/ModbusUdp"
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
<UdpSessionPage @ref=_udpSessionPage></UdpSessionPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.Description(x => x.IsCheckMessageId)) Dense HideDetails="@("auto")" @bind-Value=@_plc.IsCheckMessageId></MCheckbox>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,80 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class ModbusUdpDebugPage
{
/// <summary>
/// SerialSessionPage
/// </summary>
private UdpSessionPage _udpSessionPage;
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp _plc;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var udpSession1 = new UdpSession();//链路对象
udpSession1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
ModbusUdp plc = new(udpSession1)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
Crc16CheckEnable = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_udpSessionPage != null)
_udpSessionPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp(_udpSessionPage.GetUdpSession());
_driverDebugUIPage.Plc = _plc;
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,135 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/OPCDAClient"
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Masa.Blazor.Presets;
@using Microsoft.JSInterop;
@inherits BaseComponentBase
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Foundation.Adapter.OPCDA.Da;
@using ThingsGateway.Foundation.Extension;
@using ThingsGateway.Foundation.Serial;
@using Masa.Blazor
<OPCDAClientPage @ref=opcDAClientPage></OPCDAClientPage>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections" ShowDefaultOtherContent=false>
<ReadWriteContent>
<div class="my-1 py-1">
<MTextarea Class="mx-1 my-1" Label="变量地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@_driverDebugUIPage.Address />
<MButton Class="mx-1 my-1" Color="primary" OnClick="Add">
添加
</MButton>
<MButton Class="mx-1 my-1" Color="primary" OnClick="Remove">
移除
</MButton>
<MButton Class="mx-1 my-1" Color="primary" OnClick="ReadAsync">
组读取
</MButton>
<MTextarea Class="mx-1 mt-3 my-1" Label="值" Dense Outlined HideDetails="@("auto")" @bind-Value=@_driverDebugUIPage.WriteValue />
<MButton Class="mx-1 my-1" Color="primary" OnClick="WriteAsync">
写入
</MButton>
<MButton Class="mx-1 my-3" Color="accent" OnClick="()=>IsShowImportVariableList=!IsShowImportVariableList">
<span>查看OPC节点空间</span>
</MButton>
</div>
<MCol Class="my-1 py-1">
<MRow NoGutters>
</MRow>
</MCol>
</ReadWriteContent>
</DriverDebugUIPage>
@{
#if Plugin
<PModal @bind-Value="IsShowImportVariableList" OnCancel="() => IsShowImportVariableList = false"
Title=导入OPC变量 Height=@("700") Persistent
MaxWidth="1500"
OnSave="DownDeviceExport">
<SaveContent Context="save">
<MMenu OffsetY Context="menu">
<ActivatorContent>
<MButton @attributes="@menu.Attrs" Color="primary" Class="my-1 mx-2 " Disabled="isDownLoading" Loading="isDownLoading">
导出
<AppChevronDown></AppChevronDown>
</MButton>
</ActivatorContent>
<ChildContent>
<MList>
<MListItem Color="primary" OnClick="DownDeviceExport" Disabled="isDownLoading" Loading="isDownLoading"> 导出到excel </MListItem>
<MListItem Color="primary" OnClick="DeviceImport" Disabled="isDownLoading" Loading="isDownLoading">导入到系统</MListItem>
</MList>
</ChildContent>
</MMenu>
</SaveContent>
<ChildContent>
@if (IsShowImportVariableList)
{
<OPCDAImportVariable @ref=ImportVariable PLC="_plc"></OPCDAImportVariable>
}
</ChildContent>
</PModal>
#else
<PModal @bind-Value="IsShowImportVariableList" OnCancel="() => IsShowImportVariableList = false"
Title=浏览OPC变量 Height=@("700") Persistent
MaxWidth="1500">
<ChildContent>
@if (IsShowImportVariableList)
{
<OPCDAImportVariable @ref=ImportVariable PLC="_plc"></OPCDAImportVariable>
}
</ChildContent>
</PModal>
#endif
}
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,234 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using BlazorComponent;
using Masa.Blazor;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using ThingsGateway.Foundation.Adapter.OPCDA;
using ThingsGateway.Foundation.Adapter.OPCDA.Da;
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// OPCDA调试页面
/// </summary>
public partial class OPCDAClientDebugPage : IDisposable
{
private ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient _plc;
private DriverDebugUIPage _driverDebugUIPage;
bool IsShowImportVariableList;
private OPCDAClientPage opcDAClientPage;
private OPCDAImportVariable ImportVariable { get; set; }
[Inject]
private InitTimezone InitTimezone { get; set; }
/// <inheritdoc/>
public override void Dispose()
{
_plc.SafeDispose();
opcDAClientPage.SafeDispose();
}
/// <inheritdoc/>
public override string ToString()
{
return nameof(OPCDAClient);
}
/// <inheritdoc/>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
if (opcDAClientPage != null)
{
opcDAClientPage.LogAction = _driverDebugUIPage.LogOut;
opcDAClientPage.ValueAction = ValueOut;
}
_plc = opcDAClientPage.OPC;
//载入配置
StateHasChanged();
_driverDebugUIPage.Sections.Clear();
}
base.OnAfterRender(firstRender);
}
private void Add()
{
var tags = new Dictionary<string, List<OpcItem>>();
var tag = new OpcItem(_driverDebugUIPage.Address);
tags.Add(Guid.NewGuid().ToString(), new List<OpcItem>() { tag });
try
{
_plc.AddItems(tags);
}
catch (Exception ex)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
}
}
#if Plugin
private bool isDownLoading;
private async Task DeviceImport()
{
isDownLoading = true;
await InvokeAsync(StateHasChanged);
try
{
var data = ImportVariable?.GetImportVariableList();
if (data != null)
{
if (data?.Item2?.Count == 0)
{
await PopupService.EnqueueSnackbarAsync("无可用变量", AlertTypes.Warning);
return;
}
await _serviceScope.ServiceProvider.GetService<CollectDeviceService>().AddAsync(data?.Item1);
await _serviceScope.ServiceProvider.GetService<VariableService>().AddBatchAsync(data?.Item2);
await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
}
}
finally
{
isDownLoading = false;
}
}
private IJSObjectReference JSObjectReference;
/// <inheritdoc/>
[Inject]
protected IJSRuntime JSRuntime { get; set; }
private async Task DownDeviceExport()
{
isDownLoading = true;
await InvokeAsync(StateHasChanged);
try
{
var data = ImportVariable?.GetImportVariableList();
if (data != null)
{
if (data?.Item2?.Count == 0)
{
await PopupService.EnqueueSnackbarAsync("无可用变量", AlertTypes.Warning);
return;
}
await DownDeviceExportAsync(data?.Item1);
await DownDeviceVariableExportAsync(data?.Item2, data?.Item1.Name);
await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
}
}
finally
{
isDownLoading = false;
}
}
/// <summary>
/// 导出到excel
/// </summary>
/// <returns></returns>
public async Task DownDeviceExportAsync(CollectDevice data)
{
using var memoryStream = await _serviceScope.ServiceProvider.GetService<CollectDeviceService>().ExportFileAsync(new List<CollectDevice>() { data });
using var streamRef = new DotNetStreamReference(stream: memoryStream);
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"设备导出{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef);
}
/// <summary>
/// 导出到excel
/// </summary>
/// <returns></returns>
public async Task DownDeviceVariableExportAsync(List<DeviceVariable> data, string devName)
{
using var memoryStream = await _serviceScope.ServiceProvider.GetService<VariableService>().ExportFileAsync(data, devName);
using var streamRef = new DotNetStreamReference(stream: memoryStream);
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"变量导出{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef);
}
#endif
private async Task ReadAsync()
{
try
{
_plc.ReadItemsWithGroup();
}
catch (Exception ex)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
}
await Task.CompletedTask;
}
private void Remove()
{
_plc.RemoveItems(new List<string>() { _driverDebugUIPage.Address });
}
private void ValueOut(List<ItemReadResult> values)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + values.ToJsonString()));
if (_driverDebugUIPage.Messages.Count > 2500)
{
_driverDebugUIPage.Messages.Clear();
}
}
private async Task WriteAsync()
{
try
{
JToken tagValue = _driverDebugUIPage.WriteValue.GetJTokenFromObj();
var obj = tagValue.GetObjFromJToken();
var data = _plc.WriteItem(
new()
{
{_driverDebugUIPage.Address, obj}
}
);
if (data.Count > 0)
{
foreach (var item in data)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + item.ToJsonString()));
}
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - 写入成功"));
}
}
catch (Exception ex)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入失败:{ex}"));
}
await Task.CompletedTask;
}
}

View File

@@ -0,0 +1,46 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Foundation.Adapter.OPCDA;
@using Masa.Blazor
@implements IDisposable
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">设备配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
<MTextField Class="ma-1" Label=@node.Description(a=>a.GroupSize) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.GroupSize />
<MTextField Class="ma-1" Label=@node.Description(a=>a.UpdateRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UpdateRate />
<MTextField Class="ma-1" Label=@node.Description(a=>a.DeadBand) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.DeadBand />
<MTextField Class="ma-1" Label=@node.Description(a=>a.CheckRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.CheckRate />
<MTextField Class="ma-1" Label=@node.Description(a=>a.OPCIP) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCIP />
<MTextField Class="ma-1" Label=@node.Description(a=>a.OPCName) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCName />
<MCheckbox Class="ma-1" Label=@node.Description(a=>a.ActiveSubscribe) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe />
<MButton Class="ma-1" OnClick=@Connect Color="primary">
连接
</MButton>
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
断开
</MButton>
</MRow>
</MCard>

View File

@@ -0,0 +1,94 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using ThingsGateway.Foundation.Adapter.OPCDA;
using ThingsGateway.Foundation.Adapter.OPCDA.Da;
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// OPC
/// </summary>
public partial class OPCDAClientPage : IDisposable
{
/// <summary>
/// 日志输出
/// </summary>
public Action<LogLevel, object, string, Exception> LogAction;
/// <summary>
/// OPC
/// </summary>
public ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient OPC;
/// <summary>
/// 日志输出
/// </summary>
public Action<List<ItemReadResult>> ValueAction;
private readonly OPCDANode node = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
public void Dispose()
{
OPC.SafeDispose();
}
/// <inheritdoc/>
protected override void OnInitialized()
{
OPC = new ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient(LogOut);
OPC.DataChangedHandler += Info_DataChangedHandler;
OPC.Init(node);
base.OnInitialized();
}
private void Connect()
{
try
{
OPC.Disconnect();
GetOPCClient().Connect();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void DisConnect()
{
try
{
OPC.Disconnect();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient GetOPCClient()
{
//载入配置
OPC.Init(node);
return OPC;
}
private void Info_DataChangedHandler(List<ItemReadResult> values)
{
ValueAction?.Invoke(values);
}
private void LogOut(byte logLevel, object source, string message, Exception exception) => LogAction?.Invoke((LogLevel)logLevel, source, message, exception);
}

View File

@@ -0,0 +1,114 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.Reflection;
@inherits BaseComponentBase
@using ThingsGateway.Foundation.Adapter.OPCDA;
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
@using Masa.Blazor
<MCard Class="ma-0">
<MCardTitle Class="indigo white--text text-h6">
@PLC?.OPCNode?.ToString()
</MCardTitle>
<MRow Class="pa-4"
Justify="JustifyTypes.SpaceBetween">
<MCol Cols="12" Md="6">
<MTreeview @bind-Value=Selected @bind-Active=Actived SelectionType="SelectionType.Leaf"
Items=Nodes TItem=OPCDATagModel
Color="warning" Selectable Activatable OpenOnClick
LoadChildren=PopulateBranchAsync
TKey=BrowseElement ItemKey="r=>r.Tag"
Style="height:500px;overflow-y:auto;"
ItemText="r=>r.Name"
ItemChildren="r=>r.Nodes">
</MTreeview>
</MCol>
<MCol Cols="12" Md="6">
<MCardText Style="height:500px;overflow-y:auto;">
@if (Actived?.Count == 0)
{
<div key="title"
class="text-h6 font-weight-light grey--text pa-4 text-center">
选择左侧节点
</div>
}
else
{
<ScrollXTransition>
<MSheet Outlined Class="ma-0 pa-1">
<MRow Align="AlignTypes.Center">
<MCol>
<MListItem>
<ItemContent>
<MListItemContent>
<MListItemTitle>NodeId </MListItemTitle>
</MListItemContent>
</ItemContent>
</MListItem>
</MCol>
<MDivider Vertical Center />
<MCol>
<MLabel Class=@($"ma-1")> @Actived.FirstOrDefault().ItemName </MLabel>
</MCol>
</MRow>
</MSheet>
@if (nodeAttributes != null)
{
@foreach (var item in nodeAttributes)
{
<MSheet Outlined Class="ma-0 pa-1">
<MRow Align="AlignTypes.Center">
<MCol>
<MListItem>
<ItemContent>
<MListItemContent>
<MListItemTitle>@item.Description </MListItemTitle>
</MListItemContent>
</ItemContent>
</MListItem>
</MCol>
<MDivider Vertical Center />
<MCol>
<MLabel Class=@($"{(item.ResultID.Failed()?"red--text":"green--text")} ma-1")> @item.Value </MLabel>
</MCol>
</MRow>
</MSheet>
}
}
</ScrollXTransition>
}
</MCardText>
</MCol>
<MDivider Vertical></MDivider>
</MRow>
</MCard>
<MOverlay Absolute Value="overlay" Opacity="0.8">
<span class="green--text text--darken-2">
@("正在获取OPCDA节点...")
</span>
<MProgressCircular Indeterminate Width=6 Size="30"></MProgressCircular>
</MOverlay>

View File

@@ -0,0 +1,237 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
#if Plugin
using ThingsGateway.Plugin.OPCDA;
#endif
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// 导入变量
/// </summary>
public partial class OPCDAImportVariable
{
private List<BrowseElement> actived = new();
private ItemProperty[] nodeAttributes;
private List<OPCDATagModel> Nodes = new();
private bool overlay = true;
/// <summary>
/// opc对象
/// </summary>
[Parameter]
public ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient PLC { get; set; }
private List<BrowseElement> Actived
{
get => actived;
set
{
if (actived?.FirstOrDefault() != value?.FirstOrDefault() && value?.Count > 0)
{
actived = value;
nodeAttributes = actived.FirstOrDefault().Properties;
}
}
}
private List<BrowseElement> Selected { get; set; } = new();
#if Plugin
/// <summary>
/// 获取设备与变量列表
/// </summary>
/// <returns></returns>
public (CollectDevice, List<DeviceVariable>) GetImportVariableList()
{
var device = GetImportDevice();
//动态加载子项时,导出内容需要添加手动加载代码
foreach (var node in Selected.ToList())
{
var nodes = PopulateBranch(node.ItemName, true);
if (nodes.Count > 0)
{
Selected.AddRange(nodes.SelectMany(a => a.GetAllTags()).Select(a => a.Tag).Where(a => a != null).ToList());
}
}
var data = Selected.Select(a =>
{
if (!a.IsItem || string.IsNullOrEmpty(a.ItemName))
{
return null;
}
ProtectTypeEnum level = ProtectTypeEnum.ReadOnly;
try
{
var userAccessLevel = (accessRights)(a.Properties.FirstOrDefault(b => b.ID.Code == 5).Value);
level = userAccessLevel == accessRights.readable ? userAccessLevel == accessRights.writable ? ProtectTypeEnum.WriteOnly : ProtectTypeEnum.ReadOnly : ProtectTypeEnum.ReadWrite;
}
catch
{
}
var id = Yitter.IdGenerator.YitIdHelper.NextId();
return new DeviceVariable()
{
Name = a.Name + "-" + id,
Address = a.ItemName,
DeviceId = device.Id,
Id = id,
ProtectTypeEnum = level,
IntervalTime = 1000,
RpcWriteEnable = true,
};
}).Where(a => a != null).ToList();
return (device, data);
}
private CollectDevice GetImportDevice()
{
var id = Yitter.IdGenerator.YitIdHelper.NextId();
var data = new CollectDevice()
{
Name = PLC.OPCNode.OPCName + "-" + id,
Id = id,
Enable = true,
IsLogOut = true,
DevicePropertys = new(),
PluginName = "ThingsGateway.Plugin.OPCDA.OPCDAClient",
};
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.OPCName), Value = PLC.OPCNode.OPCName, Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.OPCName)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.OPCIP), Value = PLC.OPCNode.OPCIP, Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.OPCIP)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.ActiveSubscribe), Value = PLC.OPCNode.ActiveSubscribe.ToString(), Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.ActiveSubscribe)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.CheckRate), Value = PLC.OPCNode.CheckRate.ToString(), Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.CheckRate)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.DeadBand), Value = PLC.OPCNode.DeadBand.ToString(), Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.DeadBand)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.GroupSize), Value = PLC.OPCNode.GroupSize.ToString(), Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.GroupSize)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCDAClientProperty.UpdateRate), Value = PLC.OPCNode.UpdateRate.ToString(), Description = typeof(OPCDAClientProperty).GetProperty(nameof(OPCDAClientProperty.UpdateRate)).GetCustomAttribute<DevicePropertyAttribute>().Description });
return data;
}
#endif
/// <inheritdoc/>
protected override async Task OnInitializedAsync()
{
await Task.Factory.StartNew(async () =>
{
Nodes = PopulateBranch("");
overlay = false;
await InvokeAsync(StateHasChanged);
});
}
private List<OPCDATagModel> PopulateBranch(string sourceId, bool isAll = false)
{
List<OPCDATagModel> nodes = new()
{
new OPCDATagModel() { Name = "Browsering..." }
};
try
{
var references = PLC.GetBrowseElements(sourceId);
List<OPCDATagModel> list = new();
if (references != null)
{
for (int ii = 0; ii < references.Count; ii++)
{
var target = references[ii];
OPCDATagModel child = new()
{
Name = target.Name,
Tag = target
};
if (target.HasChildren)
{
if (isAll)
child.Nodes = PopulateBranch(target.ItemName);
else
child.Nodes = new();
}
else
{
child.Nodes = null;
}
list.Add(child);
}
}
List<OPCDATagModel> listNode = list;
nodes.Clear();
nodes.AddRange(listNode.ToArray());
return nodes;
}
catch (Exception ex)
{
return new()
{
new()
{
Name = ex.Message,
Tag = new(),
Nodes = null
}
};
}
}
private async Task PopulateBranchAsync(OPCDATagModel model)
{
await Task.Run(() =>
{
var sourceId = model.Tag.ItemName;
model.Nodes = PopulateBranch(sourceId);
});
}
internal class OPCDATagModel
{
internal string Name { get; set; }
internal string NodeId => (Tag?.ItemName)?.ToString();
internal List<OPCDATagModel> Nodes { get; set; } = new();
internal BrowseElement Tag { get; set; }
public List<OPCDATagModel> GetAllTags()
{
List<OPCDATagModel> allTags = new();
GetAllTagsRecursive(this, allTags);
return allTags;
}
private void GetAllTagsRecursive(OPCDATagModel parentTag, List<OPCDATagModel> allTags)
{
allTags.Add(parentTag);
if (parentTag.Nodes != null)
foreach (OPCDATagModel childTag in parentTag.Nodes)
{
GetAllTagsRecursive(childTag, allTags);
}
}
}
}

View File

@@ -0,0 +1,139 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/OPCUAClient"
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Masa.Blazor.Presets;
@using Microsoft.JSInterop;
@inherits BaseComponentBase
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Foundation.Adapter.OPCUA;
@using ThingsGateway.Foundation.Extension;
@using ThingsGateway.Foundation.Serial;
@using Masa.Blazor
<OPCUAClientPage @ref=opcUAClientPage></OPCUAClientPage>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections" ShowDefaultOtherContent=false>
<ReadWriteContent>
<div class="my-1 py-1">
<MTextarea Class="mx-1 my-1" Label="变量地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@_driverDebugUIPage.Address />
<MButton Class="mx-1 my-1" Color="primary" OnClick="Add">
添加
</MButton>
<MButton Class="mx-1 my-1" Color="primary" OnClick="Remove">
移除
</MButton>
<MButton Class="mx-1 my-1" Color="primary" OnClick="ReadAsync">
组读取
</MButton>
<MTextarea Class="mx-1 mt-3 my-1" Label="值" Dense Outlined HideDetails="@("auto")" @bind-Value=@_driverDebugUIPage.WriteValue />
<MButton Class="mx-1 my-1" Color="primary" OnClick="WriteAsync">
写入
</MButton>
</div>
<div class="my-1 ml-2">
<MRow Align="AlignTypes.Center" >
<MCheckbox HideDetails="@("auto")" @bind-Value=IsShowSubvariable Dense Label="是否显示子变量"/>
<MButton Class="mx-1" Color="accent" OnClick="()=>IsShowImportVariableList=!IsShowImportVariableList">
<span>查看OPC节点空间</span>
</MButton>
</MRow>
</div>
<MCol Class="my-1 py-1">
<MRow Align="AlignTypes.Center">
</MRow>
</MCol>
</ReadWriteContent>
</DriverDebugUIPage>
@{
#if Plugin
<PModal @bind-Value="IsShowImportVariableList" OnCancel="() => IsShowImportVariableList = false"
Title=导入OPC变量 Height=@("700") Persistent
MaxWidth="1500" OnSave="DownDeviceExport">
<SaveContent Context="save">
<MMenu OffsetY Context="menu">
<ActivatorContent>
<MButton @attributes="@menu.Attrs" Color="primary" Class="my-1 mx-2 " Disabled="isDownLoading" Loading="isDownLoading">
导出
<AppChevronDown></AppChevronDown>
</MButton>
</ActivatorContent>
<ChildContent>
<MList>
<MListItem Color="primary" OnClick="DownDeviceExport" Disabled="isDownLoading" Loading="isDownLoading"> 导出到excel </MListItem>
<MListItem Color="primary" OnClick="DeviceImport" Disabled="isDownLoading" Loading="isDownLoading">导入到系统</MListItem>
</MList>
</ChildContent>
</MMenu>
</SaveContent>
<ChildContent>
@if (IsShowImportVariableList)
{
<OPCUAImportVariable @ref=ImportVariable PLC="_plc"></OPCUAImportVariable>
}
</ChildContent>
</PModal>
#else
<PModal @bind-Value="IsShowImportVariableList" OnCancel="() => IsShowImportVariableList = false"
Title=导入OPC变量 Height=@("700") Persistent
MaxWidth="1500">
<ChildContent>
@if (IsShowImportVariableList)
{
<OPCUAImportVariable @ref=ImportVariable PLC="_plc" IsShowSubvariable=IsShowSubvariable></OPCUAImportVariable>
}
</ChildContent>
</PModal>
#endif
}
@code {
private readonly List<(string Code, string Language)> _sections = new();
private bool IsShowSubvariable;
}

View File

@@ -0,0 +1,239 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using BlazorComponent;
using Masa.Blazor;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Newtonsoft.Json.Linq;
using Opc.Ua;
using ThingsGateway.Foundation.Adapter.OPCUA;
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// OPCUA调试页面
/// </summary>
public partial class OPCUAClientDebugPage
{
private ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient _plc;
private DriverDebugUIPage _driverDebugUIPage;
bool IsShowImportVariableList;
private OPCUAClientPage opcUAClientPage;
private OPCUAImportVariable ImportVariable { get; set; }
[Inject]
private InitTimezone InitTimezone { get; set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public override void Dispose()
{
_plc.SafeDispose();
opcUAClientPage.SafeDispose();
base.Dispose();
}
/// <inheritdoc/>
public override string ToString()
{
return nameof(OPCUAClient);
}
/// <inheritdoc/>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
if (opcUAClientPage != null)
{
opcUAClientPage.LogAction = _driverDebugUIPage.LogOut;
_plc = opcUAClientPage.OPC;
_plc.DataChangedHandler += Plc_DataChangedHandler;
}
//载入配置
StateHasChanged();
_driverDebugUIPage.Sections.Clear();
}
base.OnAfterRender(firstRender);
}
private async Task Add()
{
if (_plc.Connected)
await _plc.AddSubscriptionAsync(Guid.NewGuid().ToString(), new[] { _driverDebugUIPage.Address });
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug, $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 未连接"));
}
}
#if Plugin
private async Task DeviceImport()
{
isDownLoading = true;
await InvokeAsync(StateHasChanged);
try
{
var data = await ImportVariable?.GetImportVariableListAsync();
if (data.Item2?.Count == 0)
{
await PopupService.EnqueueSnackbarAsync("无可用变量", AlertTypes.Warning);
return;
}
await _serviceScope.ServiceProvider.GetService<CollectDeviceService>().AddAsync(data.Item1);
await _serviceScope.ServiceProvider.GetService<VariableService>().AddBatchAsync(data.Item2);
await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
}
finally
{
isDownLoading = false;
}
}
private IJSObjectReference JSObjectReference;
private bool isDownLoading;
/// <inheritdoc/>
[Inject]
protected IJSRuntime JSRuntime { get; set; }
private async Task DownDeviceExport()
{
isDownLoading = true;
await InvokeAsync(StateHasChanged);
try
{
var data = await ImportVariable?.GetImportVariableListAsync();
if (data.Item2?.Count == 0)
{
await PopupService.EnqueueSnackbarAsync("无可用变量", AlertTypes.Warning);
return;
}
await DownDeviceExportAsync(data.Item1);
await DownDeviceVariableExportAsync(data.Item2, data.Item1.Name);
await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
}
finally
{
isDownLoading = false;
}
}
/// <summary>
/// 导出到excel
/// </summary>
/// <returns></returns>
public async Task DownDeviceExportAsync(CollectDevice data)
{
using var memoryStream = await _serviceScope.ServiceProvider.GetService<CollectDeviceService>().ExportFileAsync(new List<CollectDevice>() { data });
using var streamRef = new DotNetStreamReference(stream: memoryStream);
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"设备导出{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef);
}
/// <summary>
/// 导出到excel
/// </summary>
/// <returns></returns>
public async Task DownDeviceVariableExportAsync(List<DeviceVariable> data, string devName)
{
using var memoryStream = await _serviceScope.ServiceProvider.GetService<VariableService>().ExportFileAsync(data, devName);
using var streamRef = new DotNetStreamReference(stream: memoryStream);
JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream");
await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"变量导出{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef);
}
#endif
private void Plc_DataChangedHandler((VariableNode variableNode, DataValue dataValue, Newtonsoft.Json.Linq.JToken jToken) item)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {item.variableNode.NodeId}{item.jToken}"));
if (_driverDebugUIPage.Messages.Count > 2500)
{
_driverDebugUIPage.Messages.Clear();
}
}
private async Task ReadAsync()
{
if (_plc.Connected)
{
try
{
var data = await _plc.ReadJTokenValueAsync(new string[] { _driverDebugUIPage.Address });
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Debug,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data[0].Item1}{data[0].Item3}"));
}
catch (Exception ex)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
}
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 未连接"));
}
}
private void Remove()
{
if (_plc.Connected)
_plc.RemoveSubscription("");
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 未连接"));
}
}
private async Task WriteAsync()
{
try
{
if (_plc.Connected)
{
var data = await _plc.WriteNodeAsync(
new()
{
{ _driverDebugUIPage.Address, JToken.Parse(_driverDebugUIPage.WriteValue)}
}
);
foreach (var item in data)
{
_driverDebugUIPage.Messages.Add((item.Value.Item1 ? Microsoft.Extensions.Logging.LogLevel.Warning : Microsoft.Extensions.Logging.LogLevel.Information,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {item.Value.Item2}"));
}
}
else
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 未连接"));
}
}
catch (Exception ex)
{
_driverDebugUIPage.Messages.Add((Microsoft.Extensions.Logging.LogLevel.Error,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {ex}"));
}
}
}

View File

@@ -0,0 +1,58 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using Opc.Ua.Client;
@using Opc.Ua;
@using System.Linq;
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Foundation.Adapter.OPCUA;
@using Masa.Blazor
@implements IDisposable
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">设备配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
<MTextField Class="ma-1" Label=@node.Description(a=>a.GroupSize) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.GroupSize />
<MTextField Class="ma-1" Label=@node.Description(a=>a.UpdateRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UpdateRate />
<MTextField Class="ma-1" Label=@node.Description(a=>a.DeadBand) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.DeadBand />
<MTextField Class="ma-1" Label=@node.Description(a=>a.KeepAliveInterval) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.KeepAliveInterval />
<MTextField Class="ma-1" Label=@node.Description(a=>a.OPCUrl) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCUrl />
<MTextField Class="ma-1" Label=@node.Description(a=>a.UserName) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UserName />
<MTextField Class="ma-1" Label=@node.Description(a=>a.Password) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.Password />
<MCheckbox Class="ma-1" Label=@node.Description(a=>a.ActiveSubscribe) Dense HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe />
<MCheckbox Class="ma-1" Label=@node.Description(a=>a.IsUseSecurity) Dense HideDetails="@("auto")" @bind-Value=@node.IsUseSecurity />
<MCheckbox Class="ma-1" Label=@node.Description(a=>a.CheckDomain) Dense HideDetails="@("auto")" @bind-Value=@node.CheckDomain />
<MCheckbox Class="ma-1" Label=@node.Description(a=>a.LoadType) Dense HideDetails="@("auto")" @bind-Value=@node.LoadType />
<MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
连接
</MButton>
<MButton Class="ma-1" OnClick=@DisConnect Color="red">
断开
</MButton>
</MRow>
</MCard>

View File

@@ -0,0 +1,86 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using ThingsGateway.Foundation.Adapter.OPCUA;
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// OPCUAClientPage
/// </summary>
public partial class OPCUAClientPage : IDisposable
{
/// <summary>
/// 日志输出
/// </summary>
public Action<LogLevel, object, string, Exception> LogAction;
/// <summary>
/// OPC
/// </summary>
public ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient OPC;
private readonly OPCUANode node = new();
/// <summary>
/// <inheritdoc/>
/// </summary>
public void Dispose()
{
OPC.OpcStatusChange -= OPC_OpcStatusChange;
OPC.SafeDispose();
}
/// <inheritdoc/>
protected override void OnInitialized()
{
OPC = new ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient();
OPC.OpcStatusChange += OPC_OpcStatusChange;
base.OnInitialized();
}
private void OPC_OpcStatusChange(object sender, OpcUaStatusEventArgs e)
{
if (e.LogLevel > 0)
LogAction?.Invoke((LogLevel)e.LogLevel, null, e.Text, null);
}
private async Task ConnectAsync()
{
try
{
OPC.Disconnect();
await GetOPCClient().ConnectAsync(CancellationToken.None);
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private void DisConnect()
{
try
{
OPC.Disconnect();
}
catch (Exception ex)
{
LogAction?.Invoke(LogLevel.Error, null, null, ex);
}
}
private ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient GetOPCClient()
{
OPC.OPCNode = node;
return OPC;
}
}

View File

@@ -0,0 +1,112 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@inherits BaseComponentBase
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Opc.Ua;
@using System.Reflection;
@using ThingsGateway.Foundation.Adapter.OPCUA;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Class="ma-0">
<MCardTitle Class="indigo white--text text-h6">
@PLC?.OPCNode?.OPCUrl
</MCardTitle>
<MRow Class="pa-4"
Justify="JustifyTypes.SpaceBetween">
<MCol Cols="12" Md="6">
<MTreeview @bind-Value=Selected @bind-Active=Actived SelectionType="SelectionType.Leaf"
Items=Nodes TItem=OPCUATagModel
Color="warning" Selectable Activatable OpenOnClick
LoadChildren=PopulateBranchAsync
TKey=ReferenceDescription ItemKey="r=>r.Tag"
Style="height:500px;overflow-y:auto;"
ItemText="r=>r.Name"
ItemChildren="r=>r.Nodes">
</MTreeview>
</MCol>
<MCol Cols="12" Md="6">
<MCardText Style="height:500px;overflow-y:auto;">
@if (Actived?.Count == 0 || Actived?.FirstOrDefault()?.NodeId==null)
{
<div key="title"
class="text-h6 font-weight-light grey--text pa-4 text-center">
选择左侧节点
</div>
}
else
{
<ScrollXTransition>
<MSheet Outlined Class="ma-0 pa-1">
<MRow Align="AlignTypes.Center">
<MCol>
<MListItem>
<ItemContent>
<MListItemContent>
<MListItemTitle>NodeId </MListItemTitle>
</MListItemContent>
</ItemContent>
</MListItem>
</MCol>
<MDivider Vertical Center />
<MCol>
<MLabel Class=@($"ma-1")> @Actived.FirstOrDefault().NodeId </MLabel>
</MCol>
</MRow>
</MSheet>
@foreach (var item in nodeAttributes)
{
<MSheet Outlined Class="ma-0 pa-1">
<MRow Align="AlignTypes.Center">
<MCol>
<MListItem>
<ItemContent>
<MListItemContent>
<MListItemTitle>@item.Name </MListItemTitle>
</MListItemContent>
</ItemContent>
</MListItem>
</MCol>
<MDivider Vertical Center />
<MCol>
<MLabel Class=@($"{(StatusCode.IsBad(item.StatusCode)?"red--text":"green--text")} ma-1")> @item.Value </MLabel>
</MCol>
</MRow>
</MSheet>
}
</ScrollXTransition>
}
</MCardText>
</MCol>
<MDivider Vertical></MDivider>
</MRow>
</MCard>
<MOverlay Absolute Value="overlay" Opacity="0.8">
<span class="green--text text--darken-2">
@("正在获取OPCUA节点...")
</span>
<MProgressCircular Indeterminate Width=6
Size="30"></MProgressCircular>
</MOverlay>

View File

@@ -0,0 +1,320 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Microsoft.AspNetCore.Components;
using Opc.Ua;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ThingsGateway.Foundation.Adapter.OPCUA;
#if Plugin
using ThingsGateway.Plugin.OPCUA;
#endif
namespace ThingsGateway.Foundation.Demo;
/// <summary>
/// 导入变量
/// </summary>
public partial class OPCUAImportVariable
{
private List<ReferenceDescription> actived = new();
private OPCNodeAttribute[] nodeAttributes;
private List<OPCUATagModel> Nodes = new();
private bool overlay = true;
/// <summary>
/// opc对象
/// </summary>
[Parameter]
public ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient PLC { get; set; }
/// <summary>
/// 是否显示子变量
/// </summary>
[Parameter]
public bool IsShowSubvariable { get; set; }
private List<ReferenceDescription> Actived
{
get => actived;
set
{
if (actived?.FirstOrDefault() != value?.FirstOrDefault() && value?.Count > 0)
{
actived = value;
if (actived.FirstOrDefault().NodeId != null)
nodeAttributes = PLC.ReadNoteAttributes(actived.FirstOrDefault().NodeId.ToString());
}
}
}
private List<ReferenceDescription> Selected { get; set; } = new();
#if Plugin
/// <summary>
/// 获取设备与变量列表
/// </summary>
/// <returns></returns>
public async Task<(CollectDevice, List<DeviceVariable>)> GetImportVariableListAsync()
{
var device = GetImportDevice();
//动态加载子项时,导出内容需要添加手动加载代码
foreach (var node in Selected.ToList())
{
List<OPCUATagModel> nodes = await PopulateBranchAsync((NodeId)node.NodeId, true, IsShowSubvariable);
if (nodes.Count > 0)
{
Selected.AddRange(nodes.SelectMany(a => a.GetAllTags()).Select(a => a.Tag).Where(a => a != null).ToList());
}
}
var data = (await SelectAsync(Selected, async a =>
{
var nodeClass = (await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.NodeClass)).FirstOrDefault().Value.ToString();
if (nodeClass == nameof(NodeClass.Variable))
{
ProtectTypeEnum level = ProtectTypeEnum.ReadOnly;
DataTypeEnum dataTypeEnum = DataTypeEnum.Object;
try
{
var userAccessLevel = (AccessLevelType)(await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.UserAccessLevel)).FirstOrDefault().Value;
level = (userAccessLevel.HasFlag(AccessLevelType.CurrentRead)) ?
userAccessLevel.HasFlag(AccessLevelType.CurrentWrite) ?
ProtectTypeEnum.ReadWrite : ProtectTypeEnum.ReadOnly : ProtectTypeEnum.WriteOnly;
var dataTypeId = (Opc.Ua.NodeId)(await PLC.ReadNoteAttributeAsync(a.NodeId.ToString(), Attributes.DataType)).FirstOrDefault().Value;
var dataType = Opc.Ua.TypeInfo.GetSystemType(dataTypeId, PLC.Session.Factory);
var result = dataType != null && Enum.TryParse<DataTypeEnum>(dataType.Name, out dataTypeEnum);
if (!result)
{
dataTypeEnum = DataTypeEnum.Object;
}
}
catch
{
}
var id = Yitter.IdGenerator.YitIdHelper.NextId();
return new DeviceVariable()
{
Name = a.DisplayName.Text + "-" + id,
Address = a.NodeId.ToString(),
DeviceId = device.Id,
DataTypeEnum = dataTypeEnum,
Id = id,
ProtectTypeEnum = level,
IntervalTime = 1000,
RpcWriteEnable = true,
};
}
else
{
return null;
}
})).Where(a => a != null).ToList();
return (device, data);
}
/// <inheritdoc/>
private CollectDevice GetImportDevice()
{
var id = Yitter.IdGenerator.YitIdHelper.NextId();
var data = new CollectDevice()
{
Name = PLC.OPCNode.OPCUrl + "-" + id,
Id = id,
Enable = true,
IsLogOut = true,
DevicePropertys = new(),
PluginName = "ThingsGateway.Plugin.OPCUA.OPCUAClient",
};
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.OPCURL), Value = PLC.OPCNode.OPCUrl, Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.OPCURL)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.UserName), Value = PLC.OPCNode.UserName, Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.UserName)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.Password), Value = PLC.OPCNode.Password, Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.Password)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.CheckDomain), Value = PLC.OPCNode.CheckDomain.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.CheckDomain)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.LoadType), Value = PLC.OPCNode.LoadType.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.LoadType)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.IsUseSecurity), Value = PLC.OPCNode.IsUseSecurity.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.IsUseSecurity)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.ActiveSubscribe), Value = true.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.ActiveSubscribe)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.DeadBand), Value = PLC.OPCNode.DeadBand.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.DeadBand)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.GroupSize), Value = PLC.OPCNode.GroupSize.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.GroupSize)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.UpdateRate), Value = PLC.OPCNode.UpdateRate.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.UpdateRate)).GetCustomAttribute<DevicePropertyAttribute>().Description });
data.DevicePropertys.Add(new() { PropertyName = nameof(OPCUAClientProperty.KeepAliveInterval), Value = PLC.OPCNode.KeepAliveInterval.ToString(), Description = typeof(OPCUAClientProperty).GetProperty(nameof(OPCUAClientProperty.KeepAliveInterval)).GetCustomAttribute<DevicePropertyAttribute>().Description });
return data;
}
#endif
/// <summary>
/// <inheritdoc/>
/// </summary>
protected override void OnInitialized()
{
Task.Run(async () =>
{
Nodes = await PopulateBranchAsync(ObjectIds.ObjectsFolder, isShowSubvariable: IsShowSubvariable);
overlay = false;
await InvokeAsync(StateHasChanged);
});
}
private async Task<ReferenceDescriptionCollection> GetReferenceDescriptionCollectionAsync(NodeId sourceId)
{
BrowseDescription nodeToBrowse1 = new()
{
NodeId = sourceId,
BrowseDirection = BrowseDirection.Forward,
ReferenceTypeId = ReferenceTypeIds.Aggregates,
IncludeSubtypes = true,
NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.View | NodeClass.VariableType | NodeClass.DataType),
ResultMask = (uint)BrowseResultMask.All
};
BrowseDescription nodeToBrowse2 = new()
{
NodeId = sourceId,
BrowseDirection = BrowseDirection.Forward,
ReferenceTypeId = ReferenceTypeIds.Organizes,
IncludeSubtypes = true,
NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable | NodeClass.Method | NodeClass.View | NodeClass.ReferenceType | NodeClass.ObjectType | NodeClass.VariableType | NodeClass.DataType),
ResultMask = (uint)BrowseResultMask.All
};
BrowseDescriptionCollection nodesToBrowse = new()
{
nodeToBrowse1,
nodeToBrowse2
};
ReferenceDescriptionCollection references = await FormUtils.BrowseAsync(PLC.Session, nodesToBrowse, false);
return references;
}
private async Task PopulateBranchAsync(OPCUATagModel model)
{
var sourceId = (NodeId)model.Tag.NodeId;
model.Nodes = await PopulateBranchAsync(sourceId, isShowSubvariable: IsShowSubvariable);
}
private async Task<List<OPCUATagModel>> PopulateBranchAsync(NodeId sourceId, bool isAll = false, bool isShowSubvariable = false)
{
if (!PLC.Connected)
{
return new() { new() { Name = "未完成连接", Tag = new(), Nodes = null } };
}
List<OPCUATagModel> nodes = new()
{
new OPCUATagModel() { Name = "Browsering..." }
};
ReferenceDescriptionCollection references = await GetReferenceDescriptionCollectionAsync(sourceId);
List<OPCUATagModel> list = new();
if (references != null)
{
for (int ii = 0; ii < references.Count; ii++)
{
ReferenceDescription target = references[ii];
OPCUATagModel child = new()
{
Name = Utils.Format("{0}", target),
Tag = target
};
if (isShowSubvariable || target.NodeClass != NodeClass.Variable)
{
var data = await GetReferenceDescriptionCollectionAsync((NodeId)target.NodeId);
if (data != null && data.Count > 0)
{
if (isAll)
child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId, isShowSubvariable: IsShowSubvariable);
else
child.Nodes = new();
}
else
{
child.Nodes = null;
}
}
else
{
child.Nodes = null;
}
////if (target.NodeClass != NodeClass.Variable) //这个判断注释后会让子节点也是变量的情况下无法加载
//{
// var data = await GetReferenceDescriptionCollectionAsync((NodeId)target.NodeId);
// if (data != null && data.Count > 0)
// {
// if (isAll)
// child.Nodes = await PopulateBranchAsync((NodeId)target.NodeId);
// else
// child.Nodes = new();
// }
// else
// {
// child.Nodes = null;
// }
//}
////else
////{
//// child.Nodes = null;
////}
list.Add(child);
}
}
List<OPCUATagModel> listNode = list;
nodes.Clear();
nodes.AddRange(listNode.ToArray());
return nodes;
}
private async Task<TResult[]> SelectAsync<T, TResult>(IEnumerable<T> source, Func<T, Task<TResult>> selector)
{
return await Task.WhenAll(source.Select(selector));
}
internal class OPCUATagModel
{
internal string Name { get; set; }
internal string NodeId => (Tag.NodeId).ToString();
internal List<OPCUATagModel> Nodes { get; set; } = new();
internal ReferenceDescription Tag { get; set; }
public List<OPCUATagModel> GetAllTags()
{
List<OPCUATagModel> allTags = new();
GetAllTagsRecursive(this, allTags);
return allTags;
}
private void GetAllTagsRecursive(OPCUATagModel parentTag, List<OPCUATagModel> allTags)
{
allTags.Add(parentTag);
if (parentTag.Nodes != null)
foreach (OPCUATagModel childTag in parentTag.Nodes)
{
GetAllTagsRecursive(childTag, allTags);
}
}
}
}

View File

@@ -0,0 +1,75 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@page "/Siemens"
@namespace ThingsGateway.Foundation.Demo
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using ThingsGateway.Foundation.Adapter.Siemens;
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Foundation.Extension;
@using ThingsGateway.Foundation.Serial;
@using Masa.Blazor
<TcpClientPage @ref=_tcpClientPage></TcpClientPage>
<MCard Flat Class="pa-2 my-1" Style="width:100%">
<div class="mb-4">驱动配置</div>
<MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
@if (_plc != null)
{
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.Description(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.SiemensEnum" Label="@(_plc.Description(x => x.SiemensEnum))"
Items=@(typeof(SiemensEnum).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(SiemensEnum)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
<MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.Description(x => x.DataFormat))"
Items=@(typeof(DataFormat).GetEnumList())
MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
ItemText=@((u) =>u.Description)
ItemValue=@(u =>(DataFormat)u.Value)
HideDetails=@("auto") Height="30"
Dense>
</MSelect>
}
</MRow>
</MCard>
<DriverDebugUIPage @ref=_driverDebugUIPage Sections="_sections">
</DriverDebugUIPage>
@code {
private readonly List<(string Code, string Language)> _sections = new();
}

View File

@@ -0,0 +1,90 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo;
/// <inheritdoc/>
public partial class SiemensDebugPage
{
private DriverDebugUIPage _driverDebugUIPage;
private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc;
/// <summary>
/// SerialSessionPage
/// </summary>
private TcpClientPage _tcpClientPage;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_sections.Add((
"""
private static async Task ModbusClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config
.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
var tcpClient1 = new TcpClient();//链路对象
tcpClient1.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500)
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
Station = 1,
TimeOut = 3000,
IsCheckMessageId = true
};
#region
var bytesResult = await plc.ReadAsync("400001", 20);
var int32sResult = await plc.ReadInt32Async("400001", 20);
#endregion
}
""", "csharp"));
if (_tcpClientPage != null)
_tcpClientPage.LogAction = _driverDebugUIPage.LogOut;
_plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(_tcpClientPage.GetTcpClient());
_driverDebugUIPage.Plc = _plc;
//初始化
_driverDebugUIPage.Address = "M100";
int index = 0;
_driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.Address = "M" + (100 + index++));
_tcpClientPage._port = 102;
_tcpClientPage.StateHasChangedAsync();
//载入配置
StateHasChanged();
}
base.OnAfterRender(firstRender);
}
}

View File

@@ -0,0 +1,42 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@inherits LayoutComponentBase
<CascadingValue Value="IsMobile" Name="IsMobile">
<MApp>
<MErrorHandler>
@Body
</MErrorHandler>
</MApp>
</CascadingValue>
@code {
public bool IsMobile { get; set; }
[Inject]
public MasaBlazor MasaBlazor { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
MasaBlazor.BreakpointChanged += BreakpointOnOnUpdate;
}
private void BreakpointOnOnUpdate(object sender, BreakpointChangedEventArgs e)
{
IsMobile = MasaBlazor.Breakpoint.Mobile;
if (e.MobileChanged)
{
StateHasChanged();
}
}
}

View File

@@ -0,0 +1,77 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@namespace ThingsGateway.Foundation.Demo
@using System.Text;
@inherits LayoutComponentBase
@layout BaseLayout
<PPageTabsProvider>
<CascadingValue Value="@this" IsFixed>
<CascadingValue Value="@Changed" Name="Changed">
<MNavigationDrawer Color="barcolor" @bind-Value="_drawerOpen" App Width="200">
<Logo CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_TITLE=@CONFIG_TITLE HeightInt=@(IsMobile?BlazorResourceConst.AppBarHeight:BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight) />
<AppList ClassString="overflow-y-auto" Routable
StyleString=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight}px);")
Items="_navs" />
</MNavigationDrawer>
<MAppBar Color="barcolor" Style=@($"{(!(IsMobile||_drawerOpen!=true)? "left:200px;":"")}") Elevation="1" App Flat ClippedRight Dense ElevateOnScroll
MaxHeight="@(BlazorResourceConst.AppBarHeight)" Height="@(BlazorResourceConst.AppBarHeight)">
<MButton Class="mr-0" Icon Small=IsMobile OnClick=@(() => _drawerOpen = !_drawerOpen)>
<MIcon>mdi-menu</MIcon>
</MButton>
</MAppBar>
<MMain Style=@($"{(!(IsMobile||_drawerOpen!=true)? "padding-left:200px;":"")}")>
<div class="full-width">
<PageTabs @ref="_pageTabs" PageTabItems="_pageTabItems" />
</div>
<MDivider Center></MDivider>
<MCard Flat Class="overflow-y-auto overflow-x-hidden ma-auto pa-0 rounded-0" Style=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight+BlazorResourceConst.FooterHeight}px);")>
<PPageContainer PageTabs="@_pageTabs?.PPageTabs">
@Body
</PPageContainer>
</MCard>
<MSheet Class="d-flex justify-center align-center rounded-0" Style=@($"height: {BlazorResourceConst.FooterHeight}px;")>
<Foter CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE></Foter>
</MSheet>
</MMain>
</CascadingValue>
</CascadingValue>
</PPageTabsProvider>
@code {
bool Changed { get; set; }
private bool? _drawerOpen = true;
private PageTabs _pageTabs;
/// <summary>
/// IsMobile
/// </summary>
[CascadingParameter(Name = "IsMobile")]
public bool IsMobile { get; set; }
}
@code{
private string CONFIG_COPYRIGHT = "Diego";
private string CONFIG_COPYRIGHT_URL = "https://gitee.com/diego2098/ThingsGateway";
private string CONFIG_TITLE = "ThingsGateway";
}

View File

@@ -0,0 +1,234 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Demo;
public partial class MainLayout
{
private List<NavItem> _navs { get; set; } = new();
private List<PageTabItem> _pageTabItems { get; set; } = new();
protected override void OnInitialized()
{
var dataString =
"""
[
{
"Href": "/index",
"Title": "首页"
},
{
"Title": "Modbus",
"Children": [
{
"Href": "/ModbusRtu",
"Title": "ModbusRtu"
},
{
"Href": "/ModbusTcp",
"Title": "ModbusTcp"
},
{
"Href": "/ModbusRtuOverTcp",
"Title": "ModbusRtuOverTcp"
},
{
"Href": "/ModbusRtuOverUdp",
"Title": "ModbusRtuOverUdp"
},
{
"Href": "/ModbusUdp",
"Title": "ModbusUdp"
},
{
"Href": "/ModbusTcpDtu",
"Title": "ModbusTcpDtu"
},
{
"Href": "/ModbusTcpServer",
"Title": "ModbusTcpServer"
},
{
"Href": "/ModbusSerialServer",
"Title": "ModbusSerialServer"
}
]
},
{
"Title": "Siemens",
"Children": [
{
"Href": "/Siemens",
"Title": "Siemens"
}
]
},
{
"Title": "DLT645",
"Children": [
{
"Href": "/DLT645_2007",
"Title": "DLT645_2007"
},
{
"Href": "/DLT645_2007OverTcp",
"Title": "DLT645_2007OverTcp"
}
]
},
{
"Title": "OPCDA",
"Children": [
{
"Href": "/OPCDAClient",
"Title": "OPCDAClient"
}
]
},
{
"Title": "OPCUA",
"Children": [
{
"Href": "/OPCUAClient",
"Title": "OPCUAClient"
}
]
},
{
"Title": "Mqtt",
"Children": [
{
"Href": "/MqttClient",
"Title": "MqttClient"
}
]
}
]
""";
_navs = dataString.FromJsonString<List<NavItem>>();
#if Pro
var dataStringPro =
"""
[
{
"Title": "Melsec",
"Children": [
{
"Href": "/QnA3E_Binary",
"Title": "QnA3E_Binary"
}
]
},
{
"Title": "ABCIP",
"Children": [
{
"Href": "/ABCIPTCP",
"Title": "ABCIPTCP"
}
]
},
{
"Title": "Omron",
"Children": [
{
"Href": "/OmronFinsTcp",
"Title": "OmronFinsTcp"
},
{
"Href": "/OmronFinsUdp",
"Title": "OmronFinsUdp"
}
]
},
{
"Title": "Secs",
"Children": [
{
"Href": "/SecsTcp",
"Title": "SecsTcp"
}
]
},
{
"Title": "TS550",
"Children": [
{
"Href": "/TS550",
"Title": "TS550"
}
]
},
{
"Title": "Vigor",
"Children": [
{
"Href": "/VigorSerial",
"Title": "VigorSerial"
},
{
"Href": "/VigorSerialOverTcp",
"Title": "VigorSerialOverTcp"
}
]
},
{
"Title": "HZW_QTJC_01",
"Children": [
{
"Href": "/HZW_QTJC_01Serial",
"Title": "HZW_QTJC_01Serial"
},
{
"Href": "/HZW_QTJC_01SerialOverTcp",
"Title": "HZW_QTJC_01SerialOverTcp"
}
]
},
{
"Title": "LQTCP",
"Children": [
{
"Href": "/LQTCP",
"Title": "LQTCP"
}
]
},
{
"Title": "KELID2008",
"Children": [
{
"Href": "/KELID2008",
"Title": "KELID2008"
},
{
"Href": "/KELID2008OverTcp",
"Title": "KELID2008OverTcp"
}
]
},
]
""";
Navs.AddRange(dataStringPro.FromJsonString<List<NavItem>>());
#endif
_pageTabItems = _navs.PasePageTabItem();
base.OnInitialized();
}
}

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<ItemGroup>
<ProjectReference Include="..\..\admin\ThingsGateway.Components\ThingsGateway.Components.csproj" />
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
<ProjectReference Include="..\..\foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" />
<ProjectReference Include="..\..\foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,29 @@
@*
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
*@
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using BlazorComponent
@using Masa.Blazor
@using Masa.Blazor.Presets
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Components;
@using ThingsGateway.Core;
@using System.Net.Http.Json
@using System.IO;
@using System.Text.Json;
@using ThingsGateway.Foundation.Serial;
@using ThingsGateway.Foundation.Sockets;

View File

@@ -0,0 +1,16 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
global using System;
global using System.Windows.Forms;

View File

@@ -0,0 +1,79 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Drawing;
namespace ThingsGateway.Foundation.Demo.Winform
{
partial class MainFrom
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
blazorWebView1.Dispose();
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainFrom));
blazorWebView1 = new Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView();
SuspendLayout();
//
// blazorWebView1
//
blazorWebView1.Dock = DockStyle.Fill;
blazorWebView1.Location = new Point(0, 0);
blazorWebView1.Margin = new Padding(4);
blazorWebView1.Name = "blazorWebView1";
blazorWebView1.Size = new Size(1029, 529);
blazorWebView1.TabIndex = 0;
blazorWebView1.Text = "blazorWebView1";
//
// MainFrom
//
AutoScaleDimensions = new SizeF(9F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1029, 529);
Controls.Add(blazorWebView1);
Icon = (Icon)resources.GetObject("$this.Icon");
Margin = new Padding(4);
Name = "MainFrom";
Text = "Form1";
FormClosed += MainFrom_FormClosed;
ResumeLayout(false);
}
#endregion
private Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView blazorWebView1;
}
}

View File

@@ -0,0 +1,56 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
using System.Threading.Tasks;
using ThingsGateway.Components;
namespace ThingsGateway.Foundation.Demo.Winform
{
public partial class MainFrom : Form
{
public MainFrom()
{
InitializeComponent();
IServiceCollection services = null;
Serve.RunNative(a =>
{
services = a;
services.AddWindowsFormsBlazorWebView();
services.ThingsGatewayComponentsConfigureServices();
});
blazorWebView1.HostPage = "wwwroot/index.html";
blazorWebView1.Services = services.BuildServiceProvider();
this.Text = "ThingsGateway.Foundation.Demo";
blazorWebView1.RootComponents.Add<ThingsGateway.Foundation.Demo.App>("#app");
}
private void MainFrom_FormClosed(object sender, FormClosedEventArgs e)
{
Task.Run(() => { MessageBox.Show("释放资源中,稍候自动退出程序..."); });
Task.Run(async () =>
{
await Task.Delay(3000);
Process.GetCurrentProcess().Kill();
});
}
}
}

View File

@@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgvCjzYkwo82JsKPNifCjzYqwo82IcKPNgLCjzYAAAAAAAAA
AAAAAAAAAAAAAMKPNgDCjzYBwo82HsKPNknCjzZewo82QcKPNhLCjzYAwo82AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82S8KPNtPCjzbiwo8258KPNuDCjzatwo82EsKP
NgAAAAAAAAAAAAAAAADCjzYAwo82BsKPNmvCjzbbwo826MKPNtvCjzbhwo82vcKPNmDCjzYywo82AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKPNgDCjzYPwo82O8KPNs7Cjzb/wo82iMKP
Nh7CjzYCwo82AAAAAAAAAAAAwo82AMKPNgDCjzZnwo8298KPNsLCjzY6wo82GsKPNjTCjzbJwo82/8KP
NpTCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKPNgDCjzYIwo82vsKP
Nv/CjzZowo82AAAAAAAAAAAAAAAAAAAAAADCjzYAwo82JMKPNtnCjzbxwo82QcKPNgDCjzYAwo82AMKP
NpHCjzb/wo82lsKPNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwo82AMKP
NgjCjza9wo82/8KPNmjCjzYAAAAAAAAAAAAAAAAAwo82AMKPNgDCjzZ2wo82/8KPNrnCjzYKwo82AAAA
AADCjzYAwo82jcKPNv/CjzaWwo82AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADCjzYAwo82CMKPNr3Cjzb/wo82aMKPNgAAAAAAAAAAAAAAAADCjzYAwo82CcKPNrrCjzb/wo82fcKP
NgDCjzYAAAAAAMKPNgDCjzaLwo82/8KPNpbCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAMKPNgDCjzYIwo82vMKPNv/CjzZpwo82AAAAAAAAAAAAAAAAAMKPNgDCjzYfwo8238KP
Nv3CjzZRwo82AMKPNgDCjzYBwo82B8KPNpnCjzb/wo82psKPNgrCjzYAwo82AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgjCjza8wo82/8KPNmnCjzYAAAAAAAAAAAAAAAAAwo82AMKP
NjbCjzbxwo829sKPNj7CjzYAwo82AMKPNiPCjzaywo827cKPNv/Cjzbywo82qMKPNhPCjzYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82CMKPNrvCjzb/wo82acKPNgAAAAAAAAAAAAAA
AADCjzYAwo82P8KPNvfCjzbzwo82OcKPNgDCjzYAwo82D8KPNlnCjzZiwo82X8KPNmDCjzZRwo82CcKP
NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKPNgDCjzYHwo82usKPNv/CjzZpwo82AAAA
AAAAAAAAAAAAAMKPNgDCjzY+wo829sKPNvTCjzY8wo82AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgfCjza6wo82/8KP
NmnCjzYAAAAAAAAAAAAAAAAAwo82AMKPNirCjzbpwo82+MKPNkDCjzYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82B8KP
NrnCjzb/wo82acKPNgAAAAAAAAAAAAAAAADCjzYAwo82FcKPNtLCjzb/wo82VsKPNgAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNgLCjzYTwo82BMKP
NgDCjzYHwo82t8KPNv/CjzZpwo82AMKPNgDCjzYMwo82E8KPNgDCjzYCwo82n8KPNv/CjzaEwo82AMKP
NgAAAAAAwo82AMKPNgDCjzZPwo82XcKPNgLCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82F8KP
NrTCjzY6wo82AMKPNgbCjza0wo82/8KPNmnCjzYAwo82AMKPNnPCjzaawo82A8KPNgDCjzZOwo82+MKP
NsbCjzYRwo82AAAAAADCjzYAwo82DcKPNsLCjzagwo82AMKPNgAAAAAAAAAAAAAAAAAAAAAAAAAAAMKP
NgDCjzYPwo82ysKPNpPCjzYBwo82BcKPNrHCjzb/wo82acKPNgDCjzYUwo82zMKPNpPCjzYAwo82AMKP
NgrCjzanwo82/MKPNmnCjzYAwo82AMKPNgDCjzZRwo8298KPNnbCjzYAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAwo82AMKPNgDCjzaawo827cKPNmHCjzYswo82vMKPNv/CjzaEwo82K8KPNoDCjzb5wo82ZMKP
NgAAAAAAwo82AMKPNi7CjzbWwo825sKPNlnCjzYdwo82SMKPNtTCjzb9wo82UsKPNgAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAwo82AMKPNmHCjzb3wo828cKPNt/Cjzbuwo8298KPNurCjzbjwo829MKP
NurCjzY6wo82AAAAAADCjzYAwo82AMKPNjfCjza8wo826cKPNtvCjzbewo82ycKPNs7CjzYvwo82AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCjzYAwo82EsKPNj3CjzZAwo82QcKPNkDCjzY/wo82QMKP
NkDCjzY/wo82OMKPNgrCjzYAAAAAAAAAAADCjzYAwo82AMKPNg/CjzY5wo82SsKPNjDCjzYOwo82G8KP
NgXCjzYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////wH4H/8B8Af/AfAH/4f
hx/+H4cf/h8PH/4fDAf+HwwH/h8MB/4fD//+Hw///h8P/+IZD4/iGIcP4BGHH+ABwB/wAeAf8AHwH///
//////////////////////////////////8=
</value>
</data>
</root>

View File

@@ -0,0 +1,29 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Demo.Winform
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new MainFrom());
}
}
}

View File

@@ -0,0 +1,49 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<TargetFrameworks>net6.0-windows;net8.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<None Remove="favicon.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="favicon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net6.0-windows'">
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="6.0.553" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net8.0-windows'">
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="8.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="wwwroot\favicon.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\favicon.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<title>ThingsGateway.Foundation.Demo</title>
<base href="/" />
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link href="_content/Masa.Blazor/css/masa-blazor.min.css" rel="stylesheet" />
<link href="_content/ThingsGateway.Components/css/materialdesign/v7.1.96/css/materialdesignicons.min.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/css/material/icons.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/css/fontawesome/v6.4.0/css/all.min.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/style/custom.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/prism/prism-material-dark-for-masa.css" rel="stylesheet">
<link href="_content/ThingsGateway.Components/prism/prism-line-highlight.min.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<div id="blazor-error-ui">
<span>
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
</span>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webview.js" autostart="true"></script>
<script src="_content/ThingsGateway.Components/prism/prism.min.js"></script>
<script src="_content/BlazorComponent/js/blazor-component.js"></script>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<Project>
<PropertyGroup>
<Version>4.0.0.0</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
<TargetFrameworks>net45;netstandard2.0;net6.0;net8.0;</TargetFrameworks>
<Description>
ThingsGateway.Foundation是工业设备通讯类库归属于ThingsGateway边缘网关项目说明文档https://diego2098.gitee.io/thingsgateway-docs/
</Description>
<Authors>Diego</Authors>
<Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright>
<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSource>true</EmbedUntrackedSource>
<EmbedAllSources>true</EmbedAllSources>
<RepositoryType>Gitee</RepositoryType>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
<IncludeSymbols>true</IncludeSymbols>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway-docs/</PackageProjectUrl>
<PackageTags>ThingsGateway;Diego;dotNET China;Blazor;设备采集;边缘网关</PackageTags>
<SignAssembly>True</SignAssembly>
<DelaySign>False</DelaySign>
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
<PackageOutputPath>..\..\nupkgs</PackageOutputPath>
<AssemblyOriginatorKeyFile>..\..\..\snks/ThingsGateway.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugSymbols>True</DebugSymbols>
<DebugType>Embedded</DebugType>
<EmbedAllSources>True</EmbedAllSources>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,56 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// 控制码
/// </summary>
internal enum ControlCode : byte
{
/// <summary>
/// 读数据
/// </summary>
Read = 0x11,
/// <summary>
/// 读后续数据
/// </summary>
ReadSub = 0x12,
/// <summary>
/// 读站号
/// </summary>
ReadStation = 0x13,
/// <summary>
/// 写数据
/// </summary>
Write = 0x14,
/// <summary>
/// 写站号
/// </summary>
WriteStation = 0x15,
/// <summary>
/// 广播校时
/// </summary>
BroadcastTime = 0x08,
/// <summary>
/// 冻结
/// </summary>
Freeze = 0x16,
/// <summary>
/// 更新波特率
/// </summary>
WriteBaudRate = 0x17,
/// <summary>
/// 更新密码
/// </summary>
WritePassword = 0x18,
}

View File

@@ -0,0 +1,179 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007
/// </summary>
public class DLT645_2007 : ReadWriteDevicesSerialSessionBase, IDLT645_2007
{
/// <summary>
/// DLT645_2007
/// </summary>
/// <param name="serialSession"></param>
public DLT645_2007(SerialSession serialSession) : base(serialSession)
{
ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <inheritdoc/>
[Description("前导符报文头")]
public bool EnableFEHead { get; set; }
/// <inheritdoc/>
[Description("操作员代码")]
public string OperCode { get; set; }
/// <inheritdoc/>
[Description("写入密码")]
public string Password { get; set; }
/// <inheritdoc/>
[Description("通讯地址")]
public string Station { get; set; }
/// <inheritdoc/>
public override string GetAddressDescription()
{
return base.GetAddressDescription() + Environment.NewLine + DLT645_2007Util.GetAddressDescription();
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack, defaultIntervalTime);
}
/// <inheritdoc/>
public override void SetDataAdapter(ISocketClient socketClient = default)
{
var dataHandleAdapter = new DLT645_2007DataHandleAdapter
{
EnableFEHead = EnableFEHead
};
SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
}
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.Read(this, address, length, cancellationToken);
}
/// <inheritdoc/>
public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.ReadAsync(this, address, length, cancellationToken);
}
/// <inheritdoc/>
public override OperResult Write(string address, string value, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.Write(this, address, value, cancellationToken);
}
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.WriteAsync(this, address, value, cancellationToken);
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => throw new NotImplementedException();
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => throw new NotImplementedException();
#region
/// <inheritdoc cref="DLT645_2007Util.BroadcastTime(IDLT645_2007,DateTime, CancellationToken)"/>
public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.BroadcastTime(this, dateTime, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.FreezeAsync(IDLT645_2007,DateTime, CancellationToken)"/>
public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.FreezeAsync(this, dateTime, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.ReadDeviceStationAsync(IDLT645_2007, CancellationToken)"/>
public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.ReadDeviceStationAsync(this, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.WriteBaudRateAsync(IDLT645_2007, int, CancellationToken)"/>
public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.WriteBaudRateAsync(this, baudRate, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.WriteDeviceStationAsync(IDLT645_2007, string, CancellationToken)"/>
public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.WriteDeviceStationAsync(this, station, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.WritePasswordAsync(IDLT645_2007, byte,string,string, CancellationToken)"/>
public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.WritePasswordAsync(this, level, oldPassword, newPassword, cancellationToken);
}
#endregion
}

View File

@@ -0,0 +1,109 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007Address
/// </summary>
public class DLT645_2007Address : DeviceAddressBase
{
/// <summary>
/// <inheritdoc/>
/// </summary>
public DLT645_2007Address()
{
}
/// <summary>
/// 数据标识
/// </summary>
public byte[] DataId { get; set; } = new byte[0];
/// <summary>
/// 反转解析
/// </summary>
public bool Reverse { get; set; } = true;
/// <summary>
/// 站号信息
/// </summary>
public byte[] Station { get; set; } = new byte[0];
/// <summary>
/// 解析地址
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public static DLT645_2007Address ParseFrom(string address)
{
DLT645_2007Address dlt645_2007Address = new();
byte[] array;
array = new byte[0];
if (address.IndexOf(';') < 0)
{
array = address.ByHexStringToBytes().Reverse().ToArray();
}
else
{
string[] strArray = address.SplitStringBySemicolon();
for (int index = 0; index < strArray.Length; ++index)
{
if (strArray[index].ToUpper().StartsWith("S="))
{
var station = strArray[index].Substring(2);
if (station.IsNullOrEmpty()) station = string.Empty;
if (station.Length < 12)
station = station.PadLeft(12, '0');
dlt645_2007Address.Station = station.ByHexStringToBytes().Reverse().ToArray();
}
else if (strArray[index].Contains("r="))
{
dlt645_2007Address.Reverse = strArray[index].Substring(2).ToBool(false);
}
else if (!strArray[index].Contains("="))
{
array = strArray[index].ByHexStringToBytes().Reverse().ToArray();
}
}
}
dlt645_2007Address.DataId = array;
return dlt645_2007Address;
}
/// <inheritdoc/>
public override string ToString()
{
StringBuilder stringGeter = new();
if (Station.Length > 0)
{
stringGeter.Append($"s={Station.Reverse().ToArray().ToHexString()};");
}
if (DataId.Length > 0)
{
stringGeter.Append($"{DataId.Reverse().ToArray().ToHexString()};");
}
if (!Reverse)
{
stringGeter.Append($"s={Reverse};");
}
return stringGeter.ToString();
}
}

View File

@@ -0,0 +1,151 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007
/// </summary>
public class DLT645_2007BitConverter : ThingsGatewayBitConverter
{
/// <summary>
/// DLT645_2007
/// </summary>
public DLT645_2007BitConverter(EndianType endianType) : base(endianType)
{
}
/// <inheritdoc/>
public override short ToInt16(byte[] buffer, int offset)
{
return Convert.ToInt16(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override ushort ToUInt16(byte[] buffer, int offset)
{
return Convert.ToUInt16(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override float ToSingle(byte[] buffer, int offset)
{
return Convert.ToSingle(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override long ToInt64(byte[] buffer, int offset)
{
return Convert.ToInt64(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override int ToInt32(byte[] buffer, int offset)
{
return Convert.ToInt32(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override uint ToUInt32(byte[] buffer, int offset)
{
return Convert.ToUInt32(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override ulong ToUInt64(byte[] buffer, int offset)
{
return Convert.ToUInt64(this.ToString(buffer, offset, buffer.Length));
}
/// <summary>
/// DLT645协议转换double
/// </summary>
/// <param name="buffer">带数据项标识</param>
/// <param name="offset"></param>
/// <returns></returns>
public override double ToDouble(byte[] buffer, int offset)
{
return Convert.ToDouble(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override IThingsGatewayBitConverter CopyNew()
{
return new DLT645_2007BitConverter(EndianType)
{
DataFormat = DataFormat,
BcdFormat = BcdFormat,
Encoding = Encoding,
IsStringReverseByteWord = IsStringReverseByteWord,
Length = Length,
};
}
/// <inheritdoc/>
public override string ToString(byte[] buffer)
{
return this.ToString(buffer, 0, buffer.Length);
}
/// <inheritdoc/>
public override string ToString(byte[] buffer, int offset, int length)
{
buffer = buffer.RemoveBegin(offset);
buffer = buffer.BytesAdd(-0x33);
var dataInfos = DLT645Helper.GetDataInfos(buffer);
StringBuilder stringBuilder = new();
foreach (var dataInfo in dataInfos)
{
//实际数据
var content = buffer.SelectMiddle(4, dataInfo.ByteLength).Reverse().ToArray();
if (dataInfo.IsSigned)//可能为负数
{
if (content[0] > 0x80)//最高位是表示正负
{
content[0] = (byte)(content[0] - 0x80);
if (dataInfo.Digtal == 0)//无小数点
{
stringBuilder.Append($"-{content.ToHexString()}");
}
else
{
stringBuilder.Append((-(Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString());
}
}
else
{
ToString(stringBuilder, dataInfo, content);
}
}
else
{
ToString(stringBuilder, dataInfo, content);
}
}
return stringBuilder.ToString();
static void ToString(StringBuilder stringBuilder, DataInfo dataInfo, byte[] content)
{
if (dataInfo.Digtal < 0)
{
stringBuilder.Append($"{Encoding.ASCII.GetString(content)}");
}
else if (dataInfo.Digtal == 0)//无小数点
{
stringBuilder.Append($"{content.ToHexString()}");
}
else
{
stringBuilder.Append(((Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString());
}
}
}
}

View File

@@ -0,0 +1,191 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007DataHandleAdapter
/// </summary>
internal class DLT645_2007DataHandleAdapter : ReadWriteDevicesSingleStreamDataHandleAdapter<DLT645_2007Message>
{
/// <summary>
/// 增加FE FE FE FE的报文头部
/// </summary>
[Description("前导符报文头")]
public bool EnableFEHead { get; set; }
/// <inheritdoc/>
public override byte[] PackCommand(byte[] command)
{
//打包时加上4个FE字节
if (EnableFEHead)
{
return DataTransUtil.SpliceArray(new byte[4] { 0xFE, 0xFE, 0xFE, 0xFE }, command);
}
return command;
}
/// <inheritdoc/>
protected override DLT645_2007Message GetInstance()
{
return new DLT645_2007Message();
}
/// <inheritdoc/>
protected override FilterResult UnpackResponse(DLT645_2007Message request, byte[] send, byte[] body, byte[] response)
{
//因为设备可能带有FE前导符开头这里找到0x68的位置
int headCodeIndex = -1;
if (response != null)
{
for (int index = 0; index < response.Length; index++)
{
if (response[index] == 0x68)
{
headCodeIndex = index;
break;
}
}
}
int sendHeadCodeIndex = 0;
if (send != null)
{
for (int index = 0; index < send.Length; index++)
{
if (send[index] == 0x68)
{
sendHeadCodeIndex = index;
break;
}
}
}
//帧起始符 地址域 帧起始符 控制码 数据域长度共10个字节
if (headCodeIndex < 0 || headCodeIndex + 10 > response.Length)
return FilterResult.Cache;
var len = 10 + response[headCodeIndex + 9] + 2;
if (response.Length - headCodeIndex < len)
{
return FilterResult.Cache;
}
if (response.Length - headCodeIndex >= len && response[len + headCodeIndex - 1] == 0x16)
{
//检查校验码
int sumCheck = 0;
for (int i = headCodeIndex; i < len + headCodeIndex - 2; i++)
sumCheck += response[i];
if ((byte)sumCheck != response[len + headCodeIndex - 2])
{
//校验错误
request.Message = "和校验错误";
request.ErrorCode = 999;
return FilterResult.Success;
}
if (
(response[headCodeIndex + 1] != send[sendHeadCodeIndex + 1]) ||
(response[headCodeIndex + 2] != send[sendHeadCodeIndex + 2]) ||
(response[headCodeIndex + 3] != send[sendHeadCodeIndex + 3]) ||
(response[headCodeIndex + 4] != send[sendHeadCodeIndex + 4]) ||
(response[headCodeIndex + 5] != send[sendHeadCodeIndex + 5]) ||
(response[headCodeIndex + 6] != send[sendHeadCodeIndex + 6])
)//设备地址不符合时,返回错误
{
if (
(send[sendHeadCodeIndex + 1] == 0xAA) &&
(send[sendHeadCodeIndex + 2] == 0xAA) &&
(send[sendHeadCodeIndex + 3] == 0xAA) &&
(send[sendHeadCodeIndex + 4] == 0xAA) &&
(send[sendHeadCodeIndex + 5] == 0xAA) &&
(send[sendHeadCodeIndex + 6] == 0xAA)
)//读写通讯地址例外
{
}
else
{
request.Message = "返回地址不符合规则";
request.ErrorCode = 999;
return FilterResult.Success;
}
}
if ((response[headCodeIndex + 8] != send[sendHeadCodeIndex + 8] + 0x80))//控制码不符合时,返回错误
{
request.Message = $"返回控制码0x{response[headCodeIndex + 8]:X2}请求控制码0x{send[sendHeadCodeIndex + 8]:X2},不符合规则";
request.ErrorCode = 999;
return FilterResult.Success;
}
if ((response[headCodeIndex + 8] & 0x40) == 0x40)//控制码bit6为1时返回错误
{
byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33);
var error = DLT645Helper.Get2007ErrorMessage(byte1);
request.Message = $"异常控制码0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
request.ErrorCode = 999;
return FilterResult.Success;
}
if (send[sendHeadCodeIndex + 8] == (byte)ControlCode.Read ||
send[sendHeadCodeIndex + 8] == (byte)ControlCode.Write
)
{
//数据标识不符合时,返回错误
if (
(response[headCodeIndex + 10] == send[sendHeadCodeIndex + 10]) &&
(response[headCodeIndex + 11] == send[sendHeadCodeIndex + 11]) &&
(response[headCodeIndex + 12] == send[sendHeadCodeIndex + 12]) &&
(response[headCodeIndex + 13] == send[sendHeadCodeIndex + 13])
)
{
}
else
{
request.Message = "返回数据标识不符合规则";
request.ErrorCode = 999;
return FilterResult.Success;
}
}
request.Content = response.RemoveBegin(headCodeIndex + 10).RemoveLast(response.Length + 2 - len - headCodeIndex);
request.ErrorCode = 0;
return FilterResult.Success;
}
else
{
request.ErrorCode = 999;
return FilterResult.Success;
}
}
}

View File

@@ -0,0 +1,31 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// <inheritdoc/>
/// </summary>
internal class DLT645_2007Message : MessageBase, IMessage
{
/// <inheritdoc/>
public override int HeadBytesLength => -1;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
}
}

View File

@@ -0,0 +1,180 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007
/// </summary>
public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase, IDLT645_2007
{
/// <summary>
/// DLT645_2007
/// </summary>
/// <param name="tcpClient"></param>
public DLT645_2007OverTcp(TcpClient tcpClient) : base(tcpClient)
{
ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <inheritdoc/>
[Description("前导符报文头")]
public bool EnableFEHead { get; set; }
/// <inheritdoc/>
[Description("操作员代码")]
public string OperCode { get; set; }
/// <inheritdoc/>
[Description("写入密码")]
public string Password { get; set; }
/// <inheritdoc/>
[Description("通讯地址")]
public string Station { get; set; }
/// <inheritdoc/>
public override string GetAddressDescription()
{
return base.GetAddressDescription() + Environment.NewLine + DLT645_2007Util.GetAddressDescription();
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack, defaultIntervalTime);
}
/// <inheritdoc/>
public override void SetDataAdapter(ISocketClient socketClient = default)
{
var dataHandleAdapter = new DLT645_2007DataHandleAdapter
{
EnableFEHead = EnableFEHead
};
TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
}
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.Read(this, address, length, cancellationToken);
}
/// <inheritdoc/>
public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.ReadAsync(this, address, length, cancellationToken);
}
/// <inheritdoc/>
public override OperResult Write(string address, string value, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.Write(this, address, value, cancellationToken);
}
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.WriteAsync(this, address, value, cancellationToken);
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => throw new NotImplementedException();
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => throw new NotImplementedException();
#region
/// <inheritdoc cref="DLT645_2007Util.BroadcastTime(IDLT645_2007,DateTime, CancellationToken)"/>
public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default)
{
return DLT645_2007Util.BroadcastTime(this, dateTime, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.FreezeAsync(IDLT645_2007,DateTime, CancellationToken)"/>
public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.FreezeAsync(this, dateTime, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.ReadDeviceStationAsync(IDLT645_2007, CancellationToken)"/>
public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.ReadDeviceStationAsync(this, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.WriteBaudRateAsync(IDLT645_2007, int, CancellationToken)"/>
public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.WriteBaudRateAsync(this, baudRate, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.WriteDeviceStationAsync(IDLT645_2007, string, CancellationToken)"/>
public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.WriteDeviceStationAsync(this, station, cancellationToken);
}
/// <inheritdoc cref="DLT645_2007Util.WritePasswordAsync(IDLT645_2007, byte,string,string, CancellationToken)"/>
public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
{
return await DLT645_2007Util.WritePasswordAsync(this, level, oldPassword, newPassword, cancellationToken);
}
#endregion
}

View File

@@ -0,0 +1,313 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007
/// </summary>
internal static class DLT645_2007Util
{
/// <inheritdoc/>
public static string GetAddressDescription()
{
var str = """
-----------------------------------------
02010100 A相电压
02020100 A相电流
02030000
00000000 ()
00010000 ()
""";
return Environment.NewLine + str;
}
/// <inheritdoc/>
public static OperResult<byte[]> Read(IDLT645_2007 dlt645_2007, string address, int length, CancellationToken cancellationToken = default)
{
try
{
dlt645_2007.Connect(cancellationToken);
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, dlt645_2007.Station);
if (!commandResult.IsSuccess) return commandResult;
return dlt645_2007.SendThenReturn<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public static async Task<OperResult<byte[]>> ReadAsync(IDLT645_2007 dlt645_2007, string address, int length, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, dlt645_2007.Station);
if (!commandResult.IsSuccess) return commandResult;
return await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public static OperResult Write(IDLT645_2007 dlt645_2007, string address, string value, CancellationToken cancellationToken = default)
{
try
{
dlt645_2007.Connect(cancellationToken);
dlt645_2007.Password ??= string.Empty;
dlt645_2007.OperCode ??= string.Empty;
if (dlt645_2007.Password.Length < 8)
dlt645_2007.Password = dlt645_2007.Password.PadLeft(8, '0');
if (dlt645_2007.OperCode.Length < 8)
dlt645_2007.OperCode = dlt645_2007.OperCode.PadLeft(8, '0');
var data = DataTransUtil.SpliceArray(dlt645_2007.Password.ByHexStringToBytes(), dlt645_2007.OperCode.ByHexStringToBytes());
string[] strArray = value.SplitStringBySemicolon();
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, dlt645_2007.Station, data, strArray);
if (!commandResult.IsSuccess) return commandResult;
return dlt645_2007.SendThenReturn<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public static async Task<OperResult> WriteAsync(IDLT645_2007 dlt645_2007, string address, string value, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
dlt645_2007.Password ??= string.Empty;
dlt645_2007.OperCode ??= string.Empty;
if (dlt645_2007.Password.Length < 8)
dlt645_2007.Password = dlt645_2007.Password.PadLeft(8, '0');
if (dlt645_2007.OperCode.Length < 8)
dlt645_2007.OperCode = dlt645_2007.OperCode.PadLeft(8, '0');
var data = DataTransUtil.SpliceArray(dlt645_2007.Password.ByHexStringToBytes(), dlt645_2007.OperCode.ByHexStringToBytes());
string[] strArray = value.SplitStringBySemicolon();
var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, dlt645_2007.Station, data, strArray);
if (!commandResult.IsSuccess) return commandResult;
return await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
#region
/// <summary>
/// 广播校时
/// </summary>
/// <param name="dlt645_2007">链路</param>
/// <param name="dateTime">时间</param>
/// <param name="cancellationToken">取消令箭</param>
/// <returns></returns>
public static OperResult BroadcastTime(IDLT645_2007 dlt645_2007, DateTime dateTime, CancellationToken cancellationToken = default)
{
try
{
dlt645_2007.Connect(cancellationToken);
string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().ToArray(), "999999999999".ByHexStringToBytes());
if (commandResult.IsSuccess)
{
dlt645_2007.Send(commandResult.Content);
return OperResult.CreateSuccessResult();
}
else
{
return new OperResult(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 冻结
/// </summary>
/// <param name="dlt645_2007">链路</param>
/// <param name="dateTime">时间</param>
/// <param name="cancellationToken">取消令箭</param>
/// <returns></returns>
public static async Task<OperResult> FreezeAsync(IDLT645_2007 dlt645_2007, DateTime dateTime, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
if (dlt645_2007.Station.IsNullOrEmpty()) dlt645_2007.Station = string.Empty;
if (dlt645_2007.Station.Length < 12) dlt645_2007.Station = dlt645_2007.Station.PadLeft(12, '0');
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().ToArray(), dlt645_2007.Station.ByHexStringToBytes().Reverse().ToArray());
if (!commandResult.IsSuccess) return commandResult;
return await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 读取通信地址
/// </summary>
/// <param name="dlt645_2007">链路</param>
/// <param name="cancellationToken">取消令箭</param>
/// <returns></returns>
public static async Task<OperResult<string>> ReadDeviceStationAsync(IDLT645_2007 dlt645_2007, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
if (!commandResult.IsSuccess) return new(commandResult);
var result = await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
if (result.IsSuccess)
{
var buffer = result.Content.SelectMiddle(0, 6).BytesAdd(-0x33);
return OperResult.CreateSuccessResult(buffer.Reverse().ToArray().ToHexString());
}
else
{
return new(result);
}
}
catch (Exception ex)
{
return new(ex);
}
}
/// <summary>
/// 修改波特率
/// </summary>
/// <param name="dlt645_2007">链路</param>
/// <param name="baudRate">波特率</param>
/// <param name="cancellationToken">取消令箭</param>
/// <returns></returns>
public static async Task<OperResult> WriteBaudRateAsync(IDLT645_2007 dlt645_2007, int baudRate, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
byte baudRateByte;
switch (baudRate)
{
case 600: baudRateByte = 0x02; break;
case 1200: baudRateByte = 0x04; break;
case 2400: baudRateByte = 0x08; break;
case 4800: baudRateByte = 0x10; break;
case 9600: baudRateByte = 0x20; break;
case 19200: baudRateByte = 0x40; break;
default: return new OperResult<string>($"不支持此波特率:{baudRate}");
}
if (dlt645_2007.Station.IsNullOrEmpty()) dlt645_2007.Station = string.Empty;
if (dlt645_2007.Station.Length < 12) dlt645_2007.Station = dlt645_2007.Station.PadLeft(12, '0');
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, dlt645_2007.Station.ByHexStringToBytes().Reverse().ToArray());
if (!commandResult.IsSuccess) return commandResult;
return await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 更新通信地址
/// </summary>
/// <param name="dlt645_2007">链路</param>
/// <param name="station">站号</param>
/// <param name="cancellationToken">取消令箭</param>
/// <returns></returns>
public static async Task<OperResult> WriteDeviceStationAsync(IDLT645_2007 dlt645_2007, string station, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
if (!commandResult.IsSuccess) return commandResult;
return await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 修改密码
/// </summary>
/// <param name="dlt645_2007">链路</param>
/// <param name="level">密码等级0-8</param>
/// <param name="oldPassword">旧密码</param>
/// <param name="newPassword">新密码</param>
/// <param name="cancellationToken">取消令箭</param>
/// <returns></returns>
public static async Task<OperResult> WritePasswordAsync(IDLT645_2007 dlt645_2007, byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
{
try
{
await dlt645_2007.ConnectAsync(cancellationToken);
if (dlt645_2007.Station.IsNullOrEmpty()) dlt645_2007.Station = string.Empty;
if (dlt645_2007.Station.Length < 12) dlt645_2007.Station = dlt645_2007.Station.PadLeft(12, '0');
string str = $"04000C{level + 1:D2}";
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
str.ByHexStringToBytes().Reverse().ToArray()
.SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray())
.SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray())
, dlt645_2007.Station.ByHexStringToBytes().Reverse().ToArray());
if (!commandResult.IsSuccess) return commandResult;
return await dlt645_2007.SendThenReturnAsync<DLT645_2007Message>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
#endregion
}

View File

@@ -0,0 +1,37 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Adapter.DLT645
{
/// <summary>
/// DLT645_2007
/// </summary>
public interface IDLT645_2007 : IReadWrite
{
/// <summary>
/// 增加FE FE FE FE的报文头部
/// </summary>
bool EnableFEHead { get; set; }
/// <summary>
/// 操作员代码
/// </summary>
string OperCode { get; set; }
/// <summary>
/// 写入密码
/// </summary>
string Password { get; set; }
/// <summary>
/// 通讯地址BCD码一般应该是12个字符
/// </summary>
string Station { get; set; }
}
}

View File

@@ -0,0 +1,52 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Adapter.DLT645;
internal static class PackHelper
{
/// <summary>
/// 打包变量,添加到<see href="deviceVariableSourceReads"></see>
/// </summary>
/// <param name="device"></param>
/// <param name="deviceVariables"></param>
/// <param name="maxPack">最大打包长度</param>
/// <param name="defaultIntervalTime">默认间隔时间</param>
/// <returns></returns>
public static List<T> LoadSourceRead<T, T2>(IReadWrite device, List<T2> deviceVariables, int maxPack, int defaultIntervalTime) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new()
{
var byteConverter = device.ThingsGatewayBitConverter;
var result = new List<T>();
//需要先剔除额外信息比如dataformat等
foreach (var item in deviceVariables)
{
var address = item.Address;
IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter);
item.ThingsGatewayBitConverter = transformParameter;
//item.Address = address;
item.Index = device.GetBitOffset(item.Address);
result.Add(new()
{
DeviceVariableRunTimes = new() { item },
Address = address,
Length = 1,
IntervalTimeTick = new(item.IntervalTime ?? defaultIntervalTime)
});
}
return result;
}
}

View File

@@ -0,0 +1,21 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using ThingsGateway.Foundation.Core;
global using ThingsGateway.Foundation.Serial;
global using ThingsGateway.Foundation.Sockets;

View File

@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,21 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using ThingsGateway.Foundation.Core;
global using ThingsGateway.Foundation.Serial;
global using ThingsGateway.Foundation.Sockets;

View File

@@ -0,0 +1,233 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <inheritdoc/>
public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
{
/// <inheritdoc/>
public ModbusTcpDtu(TcpService tcpService) : base(tcpService)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
ModbusTcpDtuPlugin modbusTcpSalvePlugin = new ModbusTcpDtuPlugin();
tcpService.Config.ConfigurePlugins(a =>
{
a.Add(modbusTcpSalvePlugin);
});
tcpService.Setup(tcpService.Config);
}
/// <summary>
/// 检测事务标识符
/// </summary>
[Description("检测事务标识符")]
public bool IsCheckMessageId { get; set; }
/// <summary>
/// 站号
/// </summary>
[Description("站号")]
public byte Station { get; set; } = 1;
/// <inheritdoc/>
public override string GetAddressDescription()
{
return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack, defaultIntervalTime);
}
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var mAddress = ModbusAddress.ParseFrom(address, Station);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn(mAddress.SocketId, commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var mAddress = ModbusAddress.ParseFrom(address, Station);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync(mAddress.SocketId, commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override void SetDataAdapter(ISocketClient socketClient = default)
{
if (socketClient != default)
{
ModbusTcpDataHandleAdapter dataHandleAdapter = new()
{
IsCheckMessageId = IsCheckMessageId,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
};
socketClient.SetDataHandlingAdapter(dataHandleAdapter);
}
else
{
foreach (var item in TcpService.GetClients())
{
ModbusTcpDataHandleAdapter dataHandleAdapter = new()
{
IsCheckMessageId = IsCheckMessageId,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
};
item.SetDataHandlingAdapter(dataHandleAdapter);
}
}
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var mAddress = ModbusAddress.ParseFrom(address, Station);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn(mAddress.SocketId, commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var mAddress = ModbusAddress.ParseFrom(address, Station);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn(mAddress.SocketId, commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var mAddress = ModbusAddress.ParseFrom(address, Station);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync(mAddress.SocketId, commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var mAddress = ModbusAddress.ParseFrom(address, Station);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync(mAddress.SocketId, commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
private OperResult<byte[]> SendThenReturn(string id, byte[] command, CancellationToken cancellationToken)
{
if (TcpService.TryGetSocketClient($"ID={id}", out var client))
{
SetDataAdapter(client);
return SendThenReturn<ModbusTcpMessage>(command, cancellationToken, client);
}
else
{
return new OperResult<byte[]>("客户端未连接");
}
}
private async Task<OperResult<byte[]>> SendThenReturnAsync(string id, byte[] command, CancellationToken cancellationToken)
{
if (TcpService.TryGetSocketClient($"ID={id}", out var client))
{
SetDataAdapter(client);
return await SendThenReturnAsync<ModbusTcpMessage>(command, cancellationToken, client);
}
else if (TcpService.SocketClients.Count == 1)
{
var client1 = TcpService.SocketClients.GetClients().FirstOrDefault();
if (client1 != null)
{
SetDataAdapter(client1);
return await SendThenReturnAsync<ModbusTcpMessage>(command, cancellationToken, client1);
}
}
return new OperResult<byte[]>("客户端未连接");
}
internal class ModbusTcpDtuPlugin : PluginBase, ITcpReceivingPlugin
{
public async Task OnTcpReceiving(ITcpClientBase client, ByteBlockEventArgs e)
{
if (client is ISocketClient socket)
{
if (!socket.Id.StartsWith("ID="))
{
ByteBlock byteBlock = e.ByteBlock;
var id = $"ID={byteBlock.ToArray().ToHexString()}";
socket.ResetId(id);
}
}
await e.InvokeNext();//如果本插件无法处理当前数据,请将数据转至下一个插件。
}
}
}

View File

@@ -0,0 +1,174 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <summary>
/// Modbus协议地址
/// </summary>
public class ModbusAddress : DeviceAddressBase
{
/// <summary>
/// <inheritdoc/>
/// </summary>
public ModbusAddress()
{
}
/// <summary>
/// 读取功能码
/// </summary>
public ushort AddressStart => Address.ToUShort();
/// <summary>
/// 读取功能码
/// </summary>
public byte ReadFunction { get; set; }
/// <summary>
/// 站号信息
/// </summary>
public byte Station { get; set; }
/// <summary>
/// 写入功能码
/// </summary>
public byte WriteFunction { get; set; }
/// <summary>
/// 打包临时写入,需要读取的字节长度
/// </summary>
public int ByteLength { get; set; }
/// <summary>
/// BitIndex
/// </summary>
public int BitIndex => (int)(Address.SplitStringByDelimiter().LastOrDefault().ToInt());
/// <summary>
/// 读取功能码
/// </summary>
public ushort AddressEnd => (ushort)(AddressStart + (Math.Ceiling(ByteLength / 2.0) > 0 ? Math.Ceiling(ByteLength / 2.0) : 1));
/// <summary>
/// 作为Slave时需提供的SocketId用于分辨Socket客户端通常对比的是初始链接时的注册包
/// </summary>
public string SocketId { get; set; }
/// <summary>
/// 解析地址
/// </summary>
public static ModbusAddress ParseFrom(string address, byte station)
{
ModbusAddress modbusAddress = new()
{
Station = station
};
return ParseFrom(address, modbusAddress);
}
/// <summary>
/// 解析地址
/// </summary>
public static ModbusAddress ParseFrom(string address, ModbusAddress modbusAddress = null)
{
modbusAddress ??= new();
if (address.IndexOf(';') < 0)
{
Address(address);
}
else
{
string[] strArray = address.SplitStringBySemicolon();
for (int index = 0; index < strArray.Length; ++index)
{
if (strArray[index].ToUpper().StartsWith("S="))
{
if (Convert.ToInt16(strArray[index].Substring(2)) > 0)
modbusAddress.Station = byte.Parse(strArray[index].Substring(2));
}
else if (strArray[index].ToUpper().StartsWith("W="))
{
if (Convert.ToInt16(strArray[index].Substring(2)) > 0)
modbusAddress.WriteFunction = byte.Parse(strArray[index].Substring(2));
}
else if (strArray[index].ToUpper().StartsWith("ID="))
{
modbusAddress.SocketId = strArray[index].Substring(3);
}
else if (!strArray[index].Contains("="))
{
Address(strArray[index]);
}
}
}
return modbusAddress;
void Address(string address)
{
var readF = ushort.Parse(address.Substring(0, 1));
if (readF > 4)
throw new("功能码错误");
switch (readF)
{
case 0:
modbusAddress.ReadFunction = 1;
break;
case 1:
modbusAddress.ReadFunction = 2;
break;
case 3:
modbusAddress.ReadFunction = 4;
break;
case 4:
modbusAddress.ReadFunction = 3;
break;
}
modbusAddress.Address = (double.Parse(address.Substring(1)) - 1).ToString();
}
}
/// <inheritdoc/>
public override string ToString()
{
StringBuilder stringGeter = new();
if (Station > 0)
{
stringGeter.Append($"s={Station.ToString()};");
}
if (WriteFunction > 0)
{
stringGeter.Append($"w={WriteFunction.ToString()};");
}
if (!string.IsNullOrEmpty(SocketId))
{
stringGeter.Append($"id={SocketId};");
}
stringGeter.Append(GetFunctionString(ReadFunction) + (AddressStart + 1).ToString());
return stringGeter.ToString();
}
private string GetFunctionString(int readF)
{
return readF switch
{
1 => "0",
2 => "1",
3 => "4",
4 => "3",
_ => "4",
};
}
}

View File

@@ -0,0 +1,334 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.Bool;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Modbus;
internal class ModbusHelper
{
/// <summary>
/// 添加Crc16
/// </summary>
internal static byte[] AddCrc(byte[] command)
{
return CRC16Utils.CRC16(command);
}
/// <summary>
/// 添加ModbusTcp报文头
/// </summary>
internal static byte[] AddModbusTcpHead(byte[] modbus, ushort id)
{
byte[] tcp = new byte[modbus.Length + 6];
tcp[0] = BitConverter.GetBytes(id)[1];
tcp[1] = BitConverter.GetBytes(id)[0];
tcp[4] = BitConverter.GetBytes(modbus.Length)[1];
tcp[5] = BitConverter.GetBytes(modbus.Length)[0];
modbus.CopyTo(tcp, 6);
return tcp;
}
/// <summary>
/// modbus地址格式说明
/// </summary>
/// <returns></returns>
internal static string GetAddressDescription()
{
StringBuilder stringBuilder = new();
stringBuilder.AppendLine("Modbus寄存器");
stringBuilder.AppendLine("线圈寄存器使用从 00001 开始的地址编号。");
stringBuilder.AppendLine("离散输入寄存器使用从 10001 开始的地址编号。");
stringBuilder.AppendLine("输入寄存器使用从 30001 开始的地址编号。");
stringBuilder.AppendLine("保持寄存器使用从 40001 开始的地址编号。");
stringBuilder.AppendLine("举例:");
stringBuilder.AppendLine("40001=>保持寄存器第一个寄存器");
stringBuilder.AppendLine("额外格式:");
stringBuilder.AppendLine("设备站号 比如40001;s=2; 代表设备地址为2的保持寄存器第一个寄存器");
stringBuilder.AppendLine("写入功能码 比如40001;w=16; 代表保持寄存器第一个寄存器写入值时采用0x10功能码而不是默认的0x06功能码");
return stringBuilder.ToString();
}
/// <summary>
/// 通过错误码来获取到对应的文本消息
/// </summary>
internal static string GetDescriptionByErrorCode(byte code)
{
return code switch
{
1 => "不支持的功能码",
2 => "读取寄存器越界",
3 => "读取长度超限",
4 => "读写异常",
_ => "未知错误",
};
}
/// <summary>
/// 获取modbus数据区内容返回数据需去除Crc和报文头例如01 03 02 00 01发送数据需报文头
/// </summary>
/// <param name="send">发送数据</param>
/// <param name="response">返回数据</param>
/// <returns></returns>
internal static OperResult<byte[], FilterResult> GetModbusData(byte[] send, byte[] response)
{
try
{
if (response.Length < 3)
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if (response[1] <= 0x05)
{
if ((response.Length < response[2] + 3))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
else
{
if ((response.Length < 6))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
if (send.Length == 0)
{
var result = OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success);
result.Message = "接收数据正确,但主机并没有主动请求数据";
return result;
}
if (send[0] != response[0])
return new OperResult<byte[], FilterResult>(string.Format("站号不一致", send[0], response[0])) { Content2 = FilterResult.Success };
if (send[1] != response[1])
return new OperResult<byte[], FilterResult>() { Message = "功能码不一致", Content2 = FilterResult.Success };
return OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success);
}
catch (Exception ex)
{
return new OperResult<byte[], FilterResult>(ex) { Content2 = FilterResult.Success };
}
}
/// <summary>
/// 去除Crc返回modbus数据区
/// </summary>
/// <param name="send"></param>
/// <param name="response"></param>
/// <param name="crcCheck"></param>
/// <returns></returns>
internal static OperResult<byte[], FilterResult> GetModbusRtuData(byte[] send, byte[] response, bool crcCheck = true)
{
if (response.Length < 3)
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if (response[1] <= 0x05)
{
if ((response.Length < response[2] + 5))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
else
{
if ((response.Length < 8))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
}
var data = response.SelectMiddle(0, response[2] != 0 ? response[2] + 5 : 8);
if (crcCheck && !CRC16Utils.CheckCRC16(data))
return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success };
return GetModbusData(send, data.RemoveLast(2));
}
/// <summary>
/// 获取读取报文
/// </summary>
internal static OperResult<byte[]> GetReadModbusCommand(string address, int length, byte station)
{
try
{
var mAddress = ModbusAddress.ParseFrom(address, station);
return OperResult.CreateSuccessResult(GetReadModbusCommand(mAddress, length));
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取写入布尔量报文,根据地址识别功能码
/// </summary>
internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool[] values, byte station)
{
try
{
var mAddress = ModbusAddress.ParseFrom(address, station);
//功能码或实际长度
if (values?.Length > 1 || mAddress.WriteFunction == 15)
return GetWriteBoolModbusCommand(mAddress, values, values.Length);
else
return GetWriteBoolModbusCommand(address, values[0], station);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取写入字报文,根据地址识别功能码
/// </summary>
internal static OperResult<byte[]> GetWriteModbusCommand(string address, byte[] value, byte station)
{
try
{
var mAddress = ModbusAddress.ParseFrom(address, station);
//功能码或实际长度
if (value?.Length > 2 || mAddress.WriteFunction == 16)
return OperResult.CreateSuccessResult(GetWriteModbusCommand(mAddress, value));
else
return OperResult.CreateSuccessResult(GetWriteOneModbusCommand(mAddress, value));
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取读取报文
/// </summary>
internal static byte[] GetReadModbusCommand(ModbusAddress mAddress, int length)
{
byte[] array = new byte[6]
{
(byte) mAddress.Station,
(byte) mAddress.ReadFunction,
BitConverter.GetBytes(mAddress.AddressStart)[1],
BitConverter.GetBytes(mAddress.AddressStart)[0],
BitConverter.GetBytes(length)[1],
BitConverter.GetBytes(length)[0]
};
return array;
}
/// <summary>
/// 获取05写入布尔量报文
/// </summary>
internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station)
{
try
{
if (address.IndexOf('.') <= 0)
{
var mAddress = ModbusAddress.ParseFrom(address, station);
return OperResult.CreateSuccessResult(GetWriteBoolModbusCommand(mAddress, value));
}
return new("不支持写入字寄存器的某一位");
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取05写入布尔量报文
/// </summary>
private static byte[] GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value)
{
byte[] array = new byte[6]
{
(byte) mAddress.Station,
(byte)5,
BitConverter.GetBytes(mAddress.AddressStart)[1],
BitConverter.GetBytes(mAddress.AddressStart)[0],
0,
0
};
if (value)
{
array[4] = 0xFF;
array[5] = 0;
}
else
{
array[4] = 0;
array[5] = 0;
}
return array;
}
/// <summary>
/// 获取15写入布尔量报文
/// </summary>
internal static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length)
{
try
{
byte[] numArray1 = values.BoolArrayToByte();
byte[] numArray2 = new byte[7 + numArray1.Length];
numArray2[0] = (byte)mAddress.Station;
numArray2[1] = (byte)15;
numArray2[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
numArray2[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
numArray2[4] = (byte)(length / 256);
numArray2[5] = (byte)(length % 256);
numArray2[6] = (byte)numArray1.Length;
numArray1.CopyTo(numArray2, 7);
return OperResult.CreateSuccessResult(numArray2);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// 获取16写入字报文
/// </summary>
internal static byte[] GetWriteModbusCommand(ModbusAddress mAddress, byte[] values)
{
byte[] numArray = new byte[7 + values.Length];
numArray[0] = (byte)mAddress.Station;
numArray[1] = (byte)16;
numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
numArray[4] = (byte)(values.Length / 2 / 256);
numArray[5] = (byte)(values.Length / 2 % 256);
numArray[6] = (byte)values.Length;
values.CopyTo(numArray, 7);
return numArray;
}
/// <summary>
/// 获取6写入字报文
/// </summary>
internal static byte[] GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values)
{
byte[] numArray = new byte[4 + values.Length];
numArray[0] = (byte)mAddress.Station;
numArray[1] = (byte)6;
numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
values.CopyTo(numArray, 4);
return numArray;
}
}

View File

@@ -0,0 +1,164 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <summary>
/// ModbusRtu
/// </summary>
public class ModbusRtu : ReadWriteDevicesSerialSessionBase
{
/// <summary>
/// ModbusRtu
/// </summary>
/// <param name="serialSession"></param>
public ModbusRtu(SerialSession serialSession) : base(serialSession)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <summary>
/// Crc校验
/// </summary>
[Description("Crc校验")]
public bool Crc16CheckEnable { get; set; } = true;
/// <summary>
/// 站号
/// </summary>
[Description("站号")]
public byte Station { get; set; } = 1;
/// <inheritdoc/>
public override string GetAddressDescription()
{
return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack, defaultIntervalTime);
}
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
return ModbusHelper.GetReadModbusCommand(address, length, Station).Then(a => SendThenReturn<ModbusRtuMessage>(a, cancellationToken));
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override void SetDataAdapter(ISocketClient socketClient = default)
{
ModbusRtuDataHandleAdapter dataHandleAdapter = new()
{
Crc16CheckEnable = Crc16CheckEnable,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
};
SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
}

View File

@@ -0,0 +1,85 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <summary>
/// Rtu适配器
/// </summary>
internal class ModbusRtuDataHandleAdapter : ReadWriteDevicesSingleStreamDataHandleAdapter<ModbusRtuMessage>
{
/// <summary>
/// 检测CRC
/// </summary>
public bool Crc16CheckEnable { get; set; } = true;
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public override byte[] PackCommand(byte[] command)
{
return ModbusHelper.AddCrc(command);
}
/// <inheritdoc/>
protected override ModbusRtuMessage GetInstance()
{
return new ModbusRtuMessage();
}
/// <inheritdoc/>
protected override FilterResult UnpackResponse(ModbusRtuMessage request, byte[] send, byte[] body, byte[] response)
{
//链路干扰时需剔除前缀中的多于字节,初步按站号+功能码找寻初始字节
if (send?.Length > 0)
{
int index = -1;
for (int i = 0; i < response.Length - 1; i++)
{
if (response[i] == send[0] && (response[i + 1] == send[1] || response[i + 1] == (send[1] + 0x80)))
{
index = i;
break;
}
}
if (index >= 0)
{
response = response.RemoveBegin(index);
}
//理想状态检测
var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
if (result.IsSuccess)
{
request.ErrorCode = result.ErrorCode;
request.Message = result.Message;
request.Content = result.Content;
}
else
{
request.ErrorCode = result.ErrorCode;
request.Message = result.Message;
}
return result.Content2;
}
else
{
return FilterResult.Success;
}
}
}

View File

@@ -0,0 +1,31 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <summary>
/// <inheritdoc/>
/// </summary>
internal class ModbusRtuMessage : MessageBase, IMessage
{
/// <inheritdoc/>
public override int HeadBytesLength => -1;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
}
}

View File

@@ -0,0 +1,160 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <inheritdoc/>
public class ModbusRtuOverTcp : ReadWriteDevicesTcpClientBase
{
/// <inheritdoc/>
public ModbusRtuOverTcp(TcpClient tcpClient) : base(tcpClient)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <summary>
/// Crc校验
/// </summary>
[Description("Crc校验")]
public bool Crc16CheckEnable { get; set; } = true;
/// <summary>
/// 站号
/// </summary>
[Description("站号")]
public byte Station { get; set; } = 1;
/// <inheritdoc/>
public override string GetAddressDescription()
{
return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
}
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack, defaultIntervalTime);
}
/// <inheritdoc/>
public override void SetDataAdapter(ISocketClient socketClient = default)
{
ModbusRtuDataHandleAdapter dataHandleAdapter = new()
{
Crc16CheckEnable = Crc16CheckEnable,
CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
};
TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
}

View File

@@ -0,0 +1,160 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <inheritdoc/>
public class ModbusRtuOverUdp : ReadWriteDevicesUdpSessionBase
{
/// <inheritdoc/>
public ModbusRtuOverUdp(UdpSession udpSession) : base(udpSession)
{
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <summary>
/// Crc校验
/// </summary>
[Description("Crc校验")]
public bool Crc16CheckEnable { get; set; }
/// <summary>
/// 站号
/// </summary>
[Description("站号")]
public byte Station { get; set; } = 1;
/// <inheritdoc/>
public override string GetAddressDescription()
{
return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
}
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override void SetDataAdapter(ISocketClient socketClient = default)
{
ModbusRtuOverUdpDataHandleAdapter dataHandleAdapter = new()
{
Crc16CheckEnable = Crc16CheckEnable,
};
UdpSession.Config.SetUdpDataHandlingAdapter(() =>
{
return dataHandleAdapter;
});
UdpSession.Setup(UdpSession.Config);
}
/// <inheritdoc/>
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
{
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack, defaultIntervalTime);
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
Connect(cancellationToken);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return SendThenReturn<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
{
try
{
await ConnectAsync(cancellationToken);
var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
if (!commandResult.IsSuccess) return commandResult;
return await SendThenReturnAsync<ModbusRtuMessage>(commandResult.Content, cancellationToken);
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
}

View File

@@ -0,0 +1,43 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <summary>
/// <inheritdoc/>
/// </summary>
internal class ModbusRtuOverUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAdapter<ModbusRtuMessage>
{
/// <summary>
/// 检测CRC
/// </summary>
public bool Crc16CheckEnable { get; set; } = true;
/// <inheritdoc/>
public override byte[] PackCommand(byte[] command)
{
return ModbusHelper.AddCrc(command);
}
/// <inheritdoc/>
protected override ModbusRtuMessage GetInstance()
{
return new ModbusRtuMessage();
}
/// <inheritdoc/>
protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response)
{
var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More