Compare commits

...

145 Commits

Author SHA1 Message Date
Kimdiego2098
d324537b47 更新发布版3.0.0.28 2023-10-31 17:47:07 +08:00
Kimdiego2098
d0c05685f7 更新OPCUAClient,订阅模式适配 分组 2023-10-31 10:55:50 +08:00
Kimdiego2098
1063c930b5 update 2023-10-31 00:24:00 +08:00
Kimdiego2098
79cbd44366 tcpservice停止时执行shutdown方法,修复demo发布不显示页面的问题 2023-10-30 21:31:30 +08:00
Kimdiego2098
7fdac1c5cb 添加部分Pro内容 2023-10-29 19:39:38 +08:00
Kimdiego2098
0c0cf72ebb 添加部分Pro内容 2023-10-29 19:34:17 +08:00
Kimdiego2098
8e2fe175ed 更新文档 2023-10-28 22:06:58 +08:00
Kimdiego2098
d1cff037c9 发布3.0.0.27版本;
优化设备线程启停逻辑
添加winform(blazor) demo
部分页面显示内容优化
2023-10-28 22:03:52 +08:00
Kimdiego2098
fc88a2fafa 发布3.0.0.27版本;
优化设备线程启停逻辑
添加winform(blazor) demo
部分页面显示内容优化
2023-10-28 22:00:35 +08:00
Kimdiego2098
45fcceb056 优化设备线程启停逻辑 2023-10-28 21:58:09 +08:00
Kimdiego2098
7043477038 添加部分Pro内容 2023-10-28 21:21:03 +08:00
Kimdiego2098
7dd685cf54 添加winform(blazor) demo 2023-10-28 15:20:12 +08:00
Kimdiego2098
5f5e4969c0 调整pro类库 2023-10-28 10:54:26 +08:00
Diego2098
8a53fd19e9 设备状态页面显示优化 2023-10-27 20:19:26 +08:00
Diego2098
baf4714c36 状态显示:已退出自动更新 2023-10-27 20:18:57 +08:00
Kimdiego2098
7ba9ac7a5b 报文显示限长500 2023-10-27 14:53:19 +08:00
Kimdiego2098
85b8f26e8e tcpserver 报文输出 添加 ip端口 提示 2023-10-27 14:41:35 +08:00
Kimdiego2098
594a0f1410 update the tcpserver class and add log output for start and stop 2023-10-27 14:24:26 +08:00
Kimdiego2098
d317d757d7 优化线程上下文转换 2023-10-26 19:16:24 +08:00
Kimdiego2098
fdf0ba6318 添加ConfigureAwait 2023-10-26 18:06:33 +08:00
Kimdiego2098
15bf7de5fa 优化设备导出逻辑 2023-10-26 15:15:43 +08:00
Kimdiego2098
d3402b058e 优化设备导出逻辑 2023-10-26 15:10:26 +08:00
Kimdiego2098
e7dfdd4031 3.0.0.25 2023-10-26 13:21:40 +08:00
Kimdiego2098
b2dd7b6364 Merge branch 'master' of https://gitee.com/dotnetchina/ThingsGateway 2023-10-26 13:20:54 +08:00
Kimdiego2098
9bd6d9abbf 3.0.0.25 2023-10-26 13:20:31 +08:00
Kimdiego2098
cd14428fea update 2023-10-26 13:19:18 +08:00
Kimdiego2098
19d9f03c2b s7添加错误返回码提示,组包处理 2023-10-26 13:05:06 +08:00
Kimdiego2098
0d57e72bbf 增加硬件信息 相关json配置 2023-10-26 10:54:48 +08:00
Kimdiego2098
329516a61b 更新nuget依赖 2023-10-26 09:37:01 +08:00
Kimdiego2098
d566869589 硬件信息页面添加刷新条件 2023-10-26 09:20:25 +08:00
Kimdiego2098
9cb8d8e6c7 更新文档 2023-10-25 00:53:27 +08:00
Kimdiego2098
9de3c57e5d update touchsocket 2023-10-25 00:53:17 +08:00
Kimdiego2098
f32ff92b0b <Version>3.0.0.24</Version> 2023-10-24 23:48:20 +08:00
Kimdiego2098
88d71e271e 更改S7协议 设备属性,注意删除了DstTSAP,改为较直观的 机架号/槽位号 2023-10-24 23:47:35 +08:00
Kimdiego2098
fd9c14612a 添加属性识别 16进制写入 2023-10-24 23:46:50 +08:00
Kimdiego2098
e26e5a160f 添加nuget依赖包 2023-10-24 20:50:39 +08:00
Kimdiego2098
b836bfed22 更新nuget包 2023-10-24 00:37:46 +08:00
Kimdiego2098
a4b598c6d0 调整解决方案文件夹 2023-10-24 00:13:03 +08:00
Kimdiego2098
c9ab755839 暂时屏蔽mqttserver 遗留消息错误 2023-10-23 20:51:11 +08:00
Kimdiego2098
9920edba53 调整编码 2023-10-23 20:47:00 +08:00
Kimdiego2098
12bd7280d1 调整mqttlog 2023-10-23 20:46:17 +08:00
Kimdiego2098
d30ea7f63b 调整mqttlog 2023-10-23 20:43:58 +08:00
Kimdiego2098
ebd3390db6 添加部分兼容方法 2023-10-22 02:42:16 +08:00
Kimdiego2098
9a374a9ebc 添加部分兼容方法 2023-10-22 02:26:18 +08:00
Kimdiego2098
b1bc22cb08 update touchsocket 2023-10-22 02:26:04 +08:00
Kimdiego2098
4930d53890 调整代码格式 2023-10-21 19:15:26 +08:00
Kimdiego2098
c31327b5bc update touchsocket 2023-10-21 19:08:21 +08:00
Kimdiego2098
3f2aa1f1e1 调整代码格式 2023-10-21 19:03:15 +08:00
Kimdiego2098
6e78c00a96 调整代码格式 2023-10-21 19:02:58 +08:00
Kimdiego2098
c27dde085e 3.0.0.23 2023-10-20 21:38:22 +08:00
Kimdiego2098
d26cc308c0 优化SQLDB实时表模式,插入/更新 2023-10-20 21:38:07 +08:00
Kimdiego2098
fb1efdf290 sqlsugar提示默认中文 2023-10-20 21:37:42 +08:00
Kimdiego2098
3c99f2a472 update touchsocket 2023-10-20 21:03:29 +08:00
Kimdiego2098
affe9a44e0 优化 ModbusServer 内存占用 2023-10-20 01:53:48 +08:00
Kimdiego2098
43730fa519 3.0.0.21 2023-10-20 01:19:18 +08:00
Kimdiego2098
d39aa22b09 优化OPCUAServer,取消注册,提供多url写入 2023-10-20 01:19:05 +08:00
Kimdiego2098
e232a6b6ea 更新赞助名单 2023-10-19 21:15:35 +08:00
Kimdiego2098
71ebb36fe9 更新文档 2023-10-19 20:36:28 +08:00
Kimdiego2098
78a0b86327 更新版本:3.0.0.20 2023-10-19 20:27:31 +08:00
Kimdiego2098
2636c16a97 优化modbusServer内存管理 2023-10-19 20:24:39 +08:00
Kimdiego2098
fd77c0242d update touchsocket 2023-10-19 20:23:43 +08:00
Kimdiego2098
e74819a900 update toucksocket 2023-10-18 21:51:49 +08:00
Kimdiego2098
9b7f696c9b 更新文档 2023-10-18 20:42:10 +08:00
Kimdiego2098
0230d614e7 发布驱动包 2023-10-18 18:04:37 +08:00
Diego2098
252d99ad78 !12 【轻量级 PR】:修正心跳事件中的参数
Merge pull request !12 from youthalan/N/A
2023-10-18 06:59:17 +00:00
youthalan
1ffc200350 修正心跳事件中的参数
Signed-off-by: youthalan <youthalan@126.com>
2023-10-18 06:58:03 +00:00
Kimdiego2098
807d89b2b2 更新版本号 2023-10-18 13:13:03 +08:00
Kimdiego2098
4013afa1f1 初始化 采集/上传线程时 直接返回线程控制 2023-10-18 13:11:59 +08:00
Kimdiego2098
a580927ceb 更新OPCUAClient类库 2023-10-18 13:09:25 +08:00
Kimdiego2098
bf2cf52034 更新OPCUAClient类库 2023-10-18 12:45:26 +08:00
Kimdiego2098
81bb8b7c31 更新OPCUAClient类库 2023-10-18 12:44:58 +08:00
Kimdiego2098
a825007fb5 更新版本号与nuget发布 2023-10-18 12:39:42 +08:00
Kimdiego2098
988124d96a 更新OPCUAClient类库 2023-10-18 12:38:20 +08:00
Diego2098
f0de815296 !11 补充OPCClient类库事件的缺失文件
Merge pull request !11 from youthalan/N/A
2023-10-18 04:34:34 +00:00
youthalan
0e2d58c887 补充OPCClient类库事件的缺失文件
Signed-off-by: youthalan <youthalan@126.com>
2023-10-18 04:32:39 +00:00
Diego2098
b155382626 !10 添加连接或断开事件
Merge pull request !10 from youthalan/N/A
2023-10-18 04:20:22 +00:00
youthalan
f362d740af 修改OPCUAClient类添加连接或断开事件,修改注入时不需要带参数
Signed-off-by: youthalan <youthalan@126.com>
2023-10-18 03:48:05 +00:00
Kimdiego2098
4a85e31a4f update 3.0.0.16 2023-10-18 00:38:36 +08:00
Kimdiego2098
302c270ad5 opcuaClient浏览空间 添加是否显示子变量的选项 2023-10-18 00:36:44 +08:00
Kimdiego2098
3c1517d0f3 更改日志输出内容 2023-10-18 00:15:07 +08:00
Kimdiego2098
f9fb222044 update 3.0.0.15 2023-10-18 00:07:24 +08:00
Kimdiego2098
e8edc02ba3 增加不支持单文件发布的说明 2023-10-17 23:47:24 +08:00
Kimdiego2098
95a44e3053 update tdengineDB plugin 2023-10-17 23:43:48 +08:00
Kimdiego2098
74a9fe9a87 update touchsocket 2023-10-17 23:12:19 +08:00
Kimdiego2098
4d03f9ea1a TD时序库插件,创建时间更改为主键 2023-10-17 23:08:09 +08:00
Kimdiego2098
67c96ca991 update touchsocket 2023-10-17 23:06:21 +08:00
Kimdiego2098
88fb793c68 更新nuget包 2023-10-17 21:00:50 +08:00
Kimdiego2098
d6d02d8cc5 update SQLDB 2023-10-16 20:50:10 +08:00
Kimdiego2098
c5a3f8e2e3 update touchsocket and other 2023-10-16 20:36:51 +08:00
Kimdiego2098
27e8653a1a 3.0.0.13 2023-10-16 17:44:09 +08:00
Kimdiego2098
863beda82c 增加关系库存储插件; 2023-10-16 17:40:17 +08:00
Kimdiego2098
bac84c3ecd 增加时序库存储插件; 2023-10-16 17:40:13 +08:00
Kimdiego2098
2fca2ad9f8 更新pro用户列表 2023-10-16 17:39:14 +08:00
Kimdiego2098
dd75286fe0 3.0.0.12 2023-10-16 08:47:39 +08:00
Kimdiego2098
7f91792cf1 opcuaclient添加是否加载服务端数据类型的选项 2023-10-16 08:46:46 +08:00
Kimdiego2098
0e0ccad311 fix:tcpservice dispose err 2023-10-16 08:46:32 +08:00
Diego2098
0691f72e67 !9 增加可选择安全订阅
Merge pull request !9 from youthalan/N/A
2023-10-16 00:33:19 +00:00
youthalan
7e38a51720 增加可选择安全订阅,以加快订阅速度
Signed-off-by: youthalan <youthalan@126.com>
2023-10-16 00:26:59 +00:00
Kimdiego2098
34ca8243a3 更新3.0.0.11 2023-10-15 20:26:18 +08:00
Diego2098
112fea7632 读取数据类型方法改为批量 2023-10-15 20:21:23 +08:00
Kimdiego2098
378763e4ee 同步Pro版本 2023-10-13 20:14:35 +08:00
Kimdiego2098
517bd0394d update touchsocket 2023-10-13 19:16:12 +08:00
Kimdiego2098
70adb97fb5 update nuget 2023-10-13 16:14:42 +08:00
Kimdiego2098
623d44cabe update 3.0.0.7 2023-10-13 11:54:27 +08:00
Kimdiego2098
0d479ca00b 添加三菱mc 3e帧二进制通讯协议文档 2023-10-13 11:51:51 +08:00
Kimdiego2098
8bc49ef437 update demo 2023-10-12 18:52:44 +08:00
Kimdiego2098
f83fcec786 参数名称修改 2023-10-12 14:57:58 +08:00
Kimdiego2098
93690ce40d fix:mqtt保留消息未更新/更新错误 2023-10-12 14:57:36 +08:00
Kimdiego2098
f82c5f2f27 3.0.0.6 2023-10-11 16:35:10 +08:00
Kimdiego2098
a83c1c3899 update nuget 2023-10-11 16:28:18 +08:00
Kimdiego2098
91d6aed109 调整代码执行顺序 2023-10-11 16:19:34 +08:00
Kimdiego2098
db8f8fe51d update ManageGateway 2023-10-11 10:59:33 +08:00
Kimdiego2098
4596004b17 update ManageGateway 2023-10-11 10:41:09 +08:00
Kimdiego2098
d5540906cb update 3.0.0.5 2023-10-10 21:09:34 +08:00
Kimdiego2098
90796a979d fix:modbusRtu写入返回报文缓存逻辑修复 2023-10-10 21:08:42 +08:00
Kimdiego2098
2190a87772 update touchsocket 2023-10-10 20:03:40 +08:00
Kimdiego2098
c5953b83f8 update touchsocket 2023-10-10 20:02:15 +08:00
Kimdiego2098
24bc60abf0 fix:signalR razor dispose接口 2023-10-09 18:11:23 +08:00
Kimdiego2098
31eee6b009 update uaparser 2023-10-09 10:56:22 +08:00
Kimdiego2098
c5da565a8f 添加MqttRpcDemo 2023-10-07 12:04:17 +08:00
Kimdiego2098
947cd712e1 添加清理日志任务配置参数 2023-10-06 18:28:06 +08:00
Kimdiego2098
edc208f96b update 3.0.0.2 2023-10-05 15:32:50 +08:00
Diego2098
1fb0296ee7 update Directory.Build.props 2023-10-05 15:21:51 +08:00
Kimdiego2098
6488d3df87 修复重启共享通道中的单个设备时,导致通道内其他设备变量异常 2023-10-05 00:34:12 +08:00
Kimdiego2098
56189d78e0 update opcuaclient 2023-10-04 17:12:47 +08:00
Kimdiego2098
bff18127b8 update opcuaclient 2023-10-04 16:59:15 +08:00
Kimdiego2098
363206e0ba update nuget 2023-10-04 02:04:09 +08:00
Kimdiego2098
fd3e378501 update 3.0.0.1 2023-10-04 01:42:27 +08:00
Kimdiego2098
4ba2fe4c9d 实时报警列表线程同步 2023-10-04 01:27:03 +08:00
Kimdiego2098
2c499626ad modbusRtu 适配器 过滤干扰头部数据 2023-10-04 01:26:44 +08:00
Kimdiego2098
2b581a03c3 更新种子数据 2023-10-04 01:24:34 +08:00
Kimdiego2098
450c15210a update windowsService bat 2023-10-03 19:11:42 +08:00
Kimdiego2098
65fed8cc93 update demo 2023-10-03 18:54:01 +08:00
Kimdiego2098
4b64771ea2 rpc调用提示优化 2023-10-03 18:20:39 +08:00
Kimdiego2098
f39977a6ff fix:rpc 特殊方法分类错误 2023-10-03 17:05:49 +08:00
Kimdiego2098
933b535caa update demo 2023-10-02 22:37:50 +08:00
Kimdiego2098
8abc5d2f20 update driverDebugPage 2023-10-02 18:34:55 +08:00
Kimdiego2098
d8783cd994 update opcuaClient 2023-10-02 18:30:58 +08:00
Diego2098
d5d087feb5 add s7 wstring addressSign 2023-10-01 16:54:42 +08:00
Diego2098
6ba3399df7 add s7 wstring addressSign 2023-10-01 16:49:07 +08:00
Diego2098
65124b3aa8 更新demo 2023-10-01 13:33:25 +08:00
Kimdiego2098
98597f4726 update demo csproj 2023-10-01 00:33:33 +08:00
Kimdiego2098
e7981f0d8e add EncodingMapper 2023-10-01 00:25:04 +08:00
Kimdiego2098
cf654427c3 更新文档 2023-09-30 23:28:50 +08:00
Kimdiego2098
ff2f628282 默认不启用远程更新 2023-09-30 23:23:44 +08:00
775 changed files with 30392 additions and 10043 deletions

View File

@@ -5,3 +5,99 @@ dotnet_diagnostic.CA1848.severity = none
# CA2254: 模板应为静态表达式
dotnet_diagnostic.CA2254.severity = suggestion
[*.cs]
#### 命名样式 ####
# 命名规则
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# 符号规范
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# 命名样式
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
[*.vb]
#### 命名样式 ####
# 命名规则
dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
# 符号规范
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
dotnet_naming_symbols.类型.required_modifiers =
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
dotnet_naming_symbols.非字段成员.required_modifiers =
# 命名样式
dotnet_naming_style.以_i_开始.required_prefix = I
dotnet_naming_style.以_i_开始.required_suffix =
dotnet_naming_style.以_i_开始.word_separator =
dotnet_naming_style.以_i_开始.capitalization = pascal_case
dotnet_naming_style.帕斯卡拼写法.required_prefix =
dotnet_naming_style.帕斯卡拼写法.required_suffix =
dotnet_naming_style.帕斯卡拼写法.word_separator =
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
dotnet_naming_style.帕斯卡拼写法.required_prefix =
dotnet_naming_style.帕斯卡拼写法.required_suffix =
dotnet_naming_style.帕斯卡拼写法.word_separator =
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case

View File

@@ -1,8 +1,7 @@
<Project>
<PropertyGroup>
<Version>3.0.0.0</Version>
<Version>3.0.0.28</Version>
<LangVersion>latest</LangVersion>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Authors>Diego</Authors>
<Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright>

View File

@@ -13,3 +13,4 @@
global using System;
global using ThingsGateway.Components;

View File

@@ -32,7 +32,6 @@ internal class Program
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
{
};
app.Run();
}
}

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
@@ -28,5 +29,18 @@
</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>

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -12,6 +12,8 @@
using Microsoft.AspNetCore.Components;
using ThingsGateway.Components;
namespace ThingsGateway.Foundation.Demo;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
/// <summary>
@@ -69,7 +71,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
_periodicTimer?.Dispose();
}
/// <inheritdoc/>
public void LogOut(ThingsGateway.Foundation.LogLevel logLevel, object source, string message, Exception exception)
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}"));
@@ -99,7 +101,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
catch (Exception ex)
{
Messages.Add((LogLevel.Error,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex.Message}"));
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex}"));
}
}
@@ -124,7 +126,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
catch (Exception ex)
{
Messages.Add((LogLevel.Error,
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex.Message}"));
$"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex}"));
}
}

View File

@@ -13,7 +13,7 @@
@using BlazorComponent;
@using Microsoft.AspNetCore.Components.Web;
@using Microsoft.JSInterop;
@using ThingsGateway.Foundation;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor;
@namespace ThingsGateway.Foundation.Demo
@inherits DriverDebugUIBase

View File

@@ -49,7 +49,7 @@ public partial class DriverDebugUIPage : DriverDebugUIBase
}
catch (Exception ex)
{
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex.Message));
Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex));
}
}

View File

@@ -15,7 +15,7 @@
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
<div class="mb-4">通道配置</div>

View File

@@ -15,7 +15,7 @@
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
@@ -26,10 +26,10 @@
<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>

View File

@@ -15,7 +15,7 @@
@using Microsoft.AspNetCore.Components.Web;
@using System.IO.Ports;
@using System.Collections.Concurrent;
@using ThingsGateway.Foundation;
@using ThingsGateway.Foundation.Core;
@using Masa.Blazor
<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">

View File

@@ -15,5 +15,7 @@ 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

@@ -1,12 +1,12 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD>
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQ群:605534569
//------------------------------------------------------------------------------
#endregion
@@ -26,7 +26,7 @@ public partial class MainLayout
[
{
"Href": "/index",
"Title": "<EFBFBD><EFBFBD>ҳ"
"Title": "首页"
},
{
"Title": "Modbus",
@@ -124,6 +124,15 @@ public partial class MainLayout
"Title": "OPCUAClient"
}
]
},
{
"Title": "Mqtt",
"Children": [
{
"Href": "/MqttClient",
"Title": "MqttClient"
}
]
}
]
@@ -135,6 +144,15 @@ public partial class MainLayout
var dataStringPro =
"""
[
{
"Title": "Melsec",
"Children": [
{
"Href": "/QnA3E_Binary",
"Title": "QnA3E_Binary"
}
]
},
{
"Title": "ABCIP",
"Children": [
@@ -189,19 +207,40 @@ public partial class MainLayout
]
},
{
"Title": "GasCustom",
"Title": "HZW_QTJC_01",
"Children": [
{
"Href": "/GasCustomSerial",
"Title": "GasCustomSerial"
"Href": "/HZW_QTJC_01Serial",
"Title": "HZW_QTJC_01Serial"
},
{
"Href": "/GasCustomSerialOverTcp",
"Title": "GasCustomSerialOverTcp"
"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"
}
]
},
]

View File

@@ -1,10 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
<DefineConstants>Pro</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro' AND '$(Configuration)' == 'Debug'">
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Melsec\Page\QnA3E_BinaryDebugPage.razor.cs" Link="Pages\Melsec\QnA3E_BinaryDebugPage.razor.cs" />
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Melsec\Page\QnA3E_BinaryDebugPage.razor" Link="Pages\Melsec\QnA3E_BinaryDebugPage.razor" />
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Melsec\ThingsGateway.Foundation.Adapter.Melsec.csproj" />
<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor.cs" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor.cs" />
<Content Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor" />
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.AllenBradleyCip\ThingsGateway.Foundation.Adapter.AllenBradleyCip.csproj" />
@@ -31,25 +40,51 @@
<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Vigor\ThingsGateway.Foundation.Adapter.Vigor.csproj" />
<Compile Include="..\..\PluginProGasCustom\ThingsGateway.Plugin.GasCustom\Page\GasCustomSerialDebugPage.razor.cs" Link="Pages\GasCustom\GasCustomSerialDebugPage.razor.cs" />
<Compile Include="..\..\PluginProGasCustom\ThingsGateway.Plugin.GasCustom\Page\GasCustomSerialOverTcpDebugPage.razor.cs" Link="Pages\GasCustom\GasCustomSerialOverTcpDebugPage.razor.cs" />
<Content Include="..\..\PluginProGasCustom\ThingsGateway.Plugin.GasCustom\Page\GasCustomSerialDebugPage.razor" Link="Pages\GasCustom\GasCustomSerialDebugPage.razor" />
<Content Include="..\..\PluginProGasCustom\ThingsGateway.Plugin.GasCustom\Page\GasCustomSerialOverTcpDebugPage.razor" Link="GasCustom\Vigor\GasCustomSerialOverTcpDebugPage.razor" />
<ProjectReference Include="..\..\PluginProGasCustom\ThingsGateway.Foundation.Adapter.GasCustom\ThingsGateway.Foundation.Adapter.GasCustom.csproj" />
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialDebugPage.razor.cs" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialDebugPage.razor.cs" />
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialOverTcpDebugPage.razor.cs" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialOverTcpDebugPage.razor.cs" />
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialDebugPage.razor" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialDebugPage.razor" />
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialOverTcpDebugPage.razor" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialOverTcpDebugPage.razor" />
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.HZW_QTJC_01\ThingsGateway.Foundation.Adapter.HZW_QTJC_01.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro' ">
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.LQTCP\Page\LQTCPDebugPage.razor.cs" Link="Pages\LQTCP\LQTCPDebugPage.razor.cs" />
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.LQTCP\Page\LQTCPDebugPage.razor" Link="Pages\LQTCP\LQTCPDebugPage.razor" />
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.LQTCP\ThingsGateway.Foundation.Adapter.LQTCP.csproj" />
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008DebugPage.razor.cs" Link="Pages\KELID2008\KELID2008DebugPage.razor.cs" />
<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008OverTcpDebugPage.razor.cs" Link="Pages\KELID2008\KELID2008OverTcpDebugPage.razor.cs" />
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008DebugPage.razor" Link="Pages\KELID2008\KELID2008DebugPage.razor" />
<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.KELID2008\Page\KELID2008OverTcpDebugPage.razor" Link="Pages\KELID2008\KELID2008OverTcpDebugPage.razor" />
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.KELID2008\ThingsGateway.Foundation.Adapter.KELID2008.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\MqttRpcNameVaueWithId.cs" Link="Pages\Mqtt\MqttRpcNameVaueWithId.cs" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor.cs" Link="Pages\Mqtt\MqttClientDebugPage.razor.cs" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor.cs" Link="Pages\Mqtt\MqttClientPage.razor.cs" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClient.cs" Link="Pages\Mqtt\MqttRpcClient.cs" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClientExtensions.cs" Link="Pages\Mqtt\MqttRpcClientExtensions.cs" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcTopicPair.cs" Link="Pages\Mqtt\MqttRpcTopicPair.cs" />
<Compile Include="..\..\Web\ThingsGateway.Gateway.Application\Workers\ManageGateway\MqttLoggerExtensions.cs" Link="Pages\Mqtt\MqttLoggerExtensions.cs" />
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor" Link="Pages\Mqtt\MqttClientDebugPage.razor" />
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor" Link="Pages\Mqtt\MqttClientPage.razor" />
<PackageReference Include="MQTTnet" Version="4.3.1.873" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" />
<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor" Link="Pages\DLT645\DLT645_2007DebugPage.razor" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor.cs" />
<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuDebugPage.razor.cs" />
<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor" Link="Pages\Modbus\ModbusRtuDebugPage.razor" />
<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor.cs" />
@@ -101,21 +136,24 @@
<ItemGroup>
<!--<PackageReference Include="ThingsGateway.Foundation.Adapter.DLT645" Version="*" />
<PackageReference Include="ThingsGateway.Foundation.Adapter.Modbus" Version="*" />
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCDA" Version="*" />
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCUA" Version="*" />
<PackageReference Include="ThingsGateway.Foundation.Adapter.Siemens" Version="*" />-->
<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>
<ItemGroup>
<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="wwwroot\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -19,7 +19,7 @@
@using BlazorComponent
@using Masa.Blazor
@using Masa.Blazor.Presets
@using ThingsGateway.Foundation;
@using ThingsGateway.Foundation.Core;
@using ThingsGateway.Components;
@using ThingsGateway.Core;
@using System.Net.Http.Json

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,78 @@
#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();
}
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,41 @@
#region copyright
//------------------------------------------------------------------------------
// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>
// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD>
// Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4><EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD>
// GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway
// GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway
// ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<51><C8BA>605534569
//------------------------------------------------------------------------------
#endregion
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;
using ThingsGateway.Components;
namespace ThingsGateway.Foundation.Demo.Winform
{
public partial class MainFrom : Form
{
public MainFrom()
{
InitializeComponent();
var services = new ServiceCollection();
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)
{
Application.Exit();
}
}
}

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,19 @@
using System.Windows.Forms;
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,47 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<TargetFrameworks>net7.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>
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="7.0.96" />
</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

@@ -1,9 +1,12 @@
<Project>
<PropertyGroup>
<Version>3.0.0.0</Version>
<Version>3.0.0.28</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
<Description>
ThingsGateway.Foundation是工业设备通讯类库归属于ThingsGateway边缘网关项目说明文档https://diego2098.gitee.io/thingsgateway-docs/
</Description>
<Authors>Diego</Authors>
<Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright>
@@ -16,7 +19,6 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway-docs/</PackageProjectUrl>
<PackageTags>ThingsGateway;Diego;dotNET China;Blazor;设备采集;边缘网关</PackageTags>
@@ -42,5 +44,10 @@
</None>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugSymbols>True</DebugSymbols>
<DebugType>Embedded</DebugType>
<EmbedAllSources>True</EmbedAllSources>
</PropertyGroup>
</Project>

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
@@ -36,12 +35,7 @@ public class DataInfo
}
internal static class DLT645Helper
{
internal static byte[] BytesAdd(this byte[] bytes, int value)
{
for (int index = 0; index < bytes.Length; ++index)
bytes[index] = (byte)(bytes[index] + value);
return bytes;
}
internal static string Get2007ErrorMessage(byte buffer)
{

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
using ThingsGateway.Foundation.Extension.Generic;
@@ -445,7 +444,7 @@ public class DLT645_2007 : ReadWriteDevicesSerialSessionBase
if (Station.IsNullOrEmpty()) Station = string.Empty;
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
string str = $"04000C{(level + 1):D2}";
string str = $"04000C{level + 1:D2}";
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
str.ByHexStringToBytes().Reverse().ToArray()

View File

@@ -92,15 +92,15 @@ public class DLT645_2007Address : DeviceAddressBase
StringBuilder stringGeter = new();
if (Station.Length > 0)
{
stringGeter.Append("s=" + Station.Reverse().ToArray().ToHexString() + ";");
stringGeter.Append($"s={Station.Reverse().ToArray().ToHexString()};");
}
if (DataId.Length > 0)
{
stringGeter.Append(DataId.Reverse().ToArray().ToHexString() + ";");
stringGeter.Append($"{DataId.Reverse().ToArray().ToHexString()};");
}
if (!Reverse)
{
stringGeter.Append("s=" + Reverse.ToString() + ";");
stringGeter.Append($"s={Reverse.ToString()};");
}
return stringGeter.ToString();
}

View File

@@ -134,7 +134,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
if ((response[headCodeIndex + 8] != send[sendHeadCodeIndex + 8] + 0x80))//控制码不符合时,返回错误
{
request.Message = "返回控制码:" + $"0x{response[headCodeIndex + 8]:X2},请求控制码:" + $"0x{send[sendHeadCodeIndex + 8]:X2},不符合规则";
request.Message = $"返回控制码0x{response[headCodeIndex + 8]:X2}请求控制码0x{send[sendHeadCodeIndex + 8]:X2},不符合规则";
request.ErrorCode = 999;
return FilterResult.Success;
}
@@ -146,7 +146,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
{
byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33);
var error = DLT645Helper.Get2007ErrorMessage(byte1);
request.Message = "异常控制码:" + $"0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
request.Message = $"异常控制码0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
request.ErrorCode = 999;
return FilterResult.Success;
}

View File

@@ -20,15 +20,12 @@ public class DLT645_2007Message : MessageBase, IMessage
public override int HeadBytesLength => -1;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] head)
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
}
/// <inheritdoc/>
protected override void SendBytesThen()
{
}
}

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
using ThingsGateway.Foundation.Extension.Generic;

View File

@@ -10,8 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Adapter.DLT645;
internal static class PackHelper

View File

@@ -11,9 +11,11 @@
#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

@@ -1,442 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>ThingsGateway.Foundation.Adapter.DLT645</name>
</assembly>
<members>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.DataInfo">
<summary>
解析参数
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.ByteLength">
<summary>
解析长度
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.Digtal">
<summary>
小数位
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.IsSigned">
<summary>
有符号解析
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645Helper.GetDataInfos(System.Byte[])">
<summary>
获取返回的解析信息
</summary>
<param name="buffer"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645Helper.GetDLT645_2007Command(System.String,System.Int32,System.Byte,System.String,System.Byte[],System.String[])">
<summary>
获取DLT645报文
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007">
<summary>
DLT645_2007
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.#ctor(ThingsGateway.Foundation.Serial.SerialSession)">
<summary>
DLT645_2007
</summary>
<param name="serialSession"></param>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.EnableFEHead">
<summary>
增加FE FE FE FE的报文头部
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.OperCode">
<summary>
写入需操作员代码
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.Password">
<summary>
写入密码
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.Station">
<summary>
通讯地址BCD码一般应该是12个字符
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.GetAddressDescription">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.SetDataAdapter">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.String,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Byte,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Double,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Single,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int64,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt64,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt16,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int16,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.BroadcastTime(System.DateTime,System.Threading.CancellationToken)">
<summary>
广播校时
</summary>
<param name="dateTime"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.FreezeAsync(System.DateTime,System.Threading.CancellationToken)">
<summary>
冻结
</summary>
<param name="dateTime"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadDeviceStationAsync(System.Threading.CancellationToken)">
<summary>
读取通信地址
</summary>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)">
<summary>
修改波特率
</summary>
<param name="baudRate"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)">
<summary>
更新通信地址
</summary>
<param name="station"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)">
<summary>
修改密码
</summary>
<param name="level"></param>
<param name="oldPassword"></param>
<param name="newPassword"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.ControlCode">
<summary>
控制码
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Read">
<summary>
读数据
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.ReadSub">
<summary>
读后续数据
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.ReadStation">
<summary>
读站号
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Write">
<summary>
写数据
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WriteStation">
<summary>
写站号
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.BroadcastTime">
<summary>
广播校时
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Freeze">
<summary>
冻结
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WriteBaudRate">
<summary>
更新波特率
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WritePassword">
<summary>
更新密码
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address">
<summary>
DLT645_2007Address
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor">
<summary>
<inheritdoc/>
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor(System.String,System.UInt16)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor(System.String,System.Byte[])">
<inheritdoc/>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.DataId">
<summary>
数据标识
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Reverse">
<summary>
反转解析
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Station">
<summary>
站号信息
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Parse(System.String,System.Int32)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.ParseFrom(System.String,System.Int32)">
<summary>
解析地址
</summary>
<param name="address"></param>
<param name="length"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.ToString">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter">
<summary>
DLT645_2007
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.#ctor(ThingsGateway.Foundation.EndianType)">
<summary>
DLT645_2007
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToDouble(System.Byte[],System.Int32)">
<summary>
DLT645协议转换double
</summary>
<param name="buffer">带数据项标识</param>
<param name="offset"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[])">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[],System.Int32,System.Int32)">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter">
<summary>
DLT645_2007DataHandleAdapter
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.EnableFEHead">
<summary>
增加FE FE FE FE的报文头部
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.PackCommand(System.Byte[])">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.GetInstance">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message,System.Byte[],System.Byte[],System.Byte[])">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp">
<summary>
DLT645_2007
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.#ctor(ThingsGateway.Foundation.TcpClient)">
<summary>
DLT645_2007
</summary>
<param name="tcpClient"></param>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.EnableFEHead">
<summary>
增加FE FE FE FE的报文头部
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.OperCode">
<summary>
写入需操作员代码
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.Password">
<summary>
写入密码
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.Station">
<summary>
通讯地址BCD码一般应该是12个字符
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.GetAddressDescription">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.SetDataAdapter">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.String,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Byte,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Double,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Single,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int64,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt64,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt16,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int16,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.BroadcastTime(System.DateTime,System.Threading.CancellationToken)">
<summary>
广播校时
</summary>
<param name="dateTime"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.FreezeAsync(System.DateTime,System.Threading.CancellationToken)">
<summary>
冻结
</summary>
<param name="dateTime"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadDeviceStationAsync(System.Threading.CancellationToken)">
<summary>
读取通信地址
</summary>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)">
<summary>
修改波特率
</summary>
<param name="baudRate"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)">
<summary>
更新通信地址
</summary>
<param name="station"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)">
<summary>
修改密码
</summary>
<param name="level"></param>
<param name="oldPassword"></param>
<param name="newPassword"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message">
<summary>
<inheritdoc/>
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.HeadBytesLength">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.CheckHeadBytes(System.Byte[])">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.SendBytesThen">
<inheritdoc/>
</member>
</members>
</doc>

View File

@@ -11,9 +11,11 @@
#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

@@ -147,15 +147,15 @@ public class ModbusAddress : DeviceAddressBase
StringBuilder stringGeter = new();
if (Station > 0)
{
stringGeter.Append("s=" + Station.ToString() + ";");
stringGeter.Append($"s={Station.ToString()};");
}
if (WriteFunction > 0)
{
stringGeter.Append("w=" + WriteFunction.ToString() + ";");
stringGeter.Append($"w={WriteFunction.ToString()};");
}
if (!string.IsNullOrEmpty(SocketId))
{
stringGeter.Append("id=" + SocketId + ";");
stringGeter.Append($"id={SocketId};");
}
stringGeter.Append(GetFunctionString(ReadFunction) + (AddressStart + 1).ToString());
return stringGeter.ToString();

View File

@@ -91,9 +91,17 @@ internal class ModbusHelper
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if ((response.Length < response[2] + 3))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
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)
{
@@ -109,7 +117,7 @@ internal class ModbusHelper
}
catch (Exception ex)
{
return new OperResult<byte[], FilterResult>(ex.Message) { Content2 = FilterResult.Success };
return new OperResult<byte[], FilterResult>(ex) { Content2 = FilterResult.Success };
}
}
/// <summary>
@@ -126,15 +134,20 @@ internal class ModbusHelper
if (response[1] >= 0x80)//错误码
return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success };
if ((response.Length < response[2] + 5))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
if (response[1] <= 0x05)
{
if ((response.Length < response[2] + 5))
return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
if (response[2] == 0)
}
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 && !EasyCRC16.CheckCRC16(data))
return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success };
@@ -152,7 +165,7 @@ internal class ModbusHelper
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}
/// <summary>
@@ -172,7 +185,7 @@ internal class ModbusHelper
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}
@@ -194,7 +207,7 @@ internal class ModbusHelper
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}
/// <summary>
@@ -231,7 +244,7 @@ internal class ModbusHelper
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}
@@ -283,7 +296,7 @@ internal class ModbusHelper
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;

View File

@@ -10,6 +10,8 @@
//------------------------------------------------------------------------------
#endregion
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Modbus;
/// <summary>
@@ -41,20 +43,43 @@ public class ModbusRtuDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M
/// <inheritdoc/>
protected override FilterResult UnpackResponse(ModbusRtuMessage request, byte[] send, byte[] body, byte[] response)
{
//理想状态检测
var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
if (result.IsSuccess)
//链路干扰时需剔除前缀中的多于字节,初步按站号+功能码找寻初始字节
if (send?.Length > 0)
{
request.ErrorCode = result.ErrorCode;
request.Message = result.Message;
request.Content = result.Content;
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
{
request.ErrorCode = result.ErrorCode;
request.Message = result.Message;
return FilterResult.Success;
}
return result.Content2;
}
}

View File

@@ -20,15 +20,12 @@ public class ModbusRtuMessage : MessageBase, IMessage
public override int HeadBytesLength => -1;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] head)
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
}
/// <inheritdoc/>
protected override void SendBytesThen()
{
}
}

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;

View File

@@ -11,7 +11,6 @@
#endregion
using System.Collections.Concurrent;
using System.Collections.Generic;
using ThingsGateway.Foundation.Extension.Bool;
using ThingsGateway.Foundation.Extension.Generic;
@@ -25,7 +24,7 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
/// <summary>
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
/// </summary>
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SerialSession, OperResult> WriteData;
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SerialSession, Task<OperResult>> WriteData;
/// <summary>
/// 继电器
@@ -102,62 +101,76 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
}
EasyLock easyLock = new();
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
ModbusAddress mAddress;
try
{
mAddress = ModbusAddress.ParseFrom(address, Station);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
easyLock.Wait();
ModbusAddress mAddress;
try
{
return new OperResult<byte[]>("地址错误");
mAddress = ModbusAddress.ParseFrom(address, Station);
}
Init(mAddress);
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
{
return new OperResult<byte[]>("地址错误");
}
Init(mAddress);
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
switch (mAddress.ReadFunction)
{
case 1:
byte[] bytes0 = new byte[len];
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Read(bytes0);
return OperResult.CreateSuccessResult(bytes0);
case 2:
byte[] bytes1 = new byte[len];
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Read(bytes1);
return OperResult.CreateSuccessResult(bytes1);
case 3:
byte[] bytes3 = new byte[len];
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Read(bytes3);
return OperResult.CreateSuccessResult(bytes3);
case 4:
byte[] bytes4 = new byte[len];
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Read(bytes4);
return OperResult.CreateSuccessResult(bytes4);
}
return new OperResult<byte[]>("功能码错误");
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
switch (mAddress.ReadFunction)
finally
{
case 1:
byte[] bytes0 = new byte[len];
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Read(bytes0);
return OperResult.CreateSuccessResult(bytes0);
case 2:
byte[] bytes1 = new byte[len];
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Read(bytes1);
return OperResult.CreateSuccessResult(bytes1);
case 3:
byte[] bytes3 = new byte[len];
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Read(bytes3);
return OperResult.CreateSuccessResult(bytes3);
case 4:
byte[] bytes4 = new byte[len];
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Read(bytes4);
return OperResult.CreateSuccessResult(bytes4);
easyLock.Release();
}
return new OperResult<byte[]>("功能码错误");
}
/// <inheritdoc/>
@@ -174,87 +187,108 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
}
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
{
ModbusAddress mAddress;
try
{
mAddress = ModbusAddress.ParseFrom(address, Station);
}
catch (Exception ex)
{
return new OperResult(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
easyLock.Wait();
ModbusAddress mAddress;
try
{
return new OperResult("地址错误");
mAddress = ModbusAddress.ParseFrom(address, Station);
}
Init(mAddress);
catch (Exception ex)
{
return new OperResult(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
{
return new OperResult("地址错误");
}
Init(mAddress);
}
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
{
case 3:
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
case 4:
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
}
return new OperResult("功能码错误");
}
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
finally
{
case 3:
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
case 4:
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
easyLock.Release();
}
return new OperResult("功能码错误");
}
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
{
ModbusAddress mAddress;
try
{
mAddress = ModbusAddress.ParseFrom(address, Station);
}
catch (Exception ex)
{
return (new OperResult(ex));
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
easyLock.Wait();
ModbusAddress mAddress;
try
{
return (new OperResult("地址错误"));
mAddress = ModbusAddress.ParseFrom(address, Station);
}
Init(mAddress);
catch (Exception ex)
{
return (new OperResult(ex));
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
{
return (new OperResult("地址错误"));
}
Init(mAddress);
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
{
case 1:
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
case 2:
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
}
return new OperResult("功能码错误");
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
finally
{
case 1:
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
case 2:
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
easyLock.Release();
}
return new OperResult("功能码错误");
}
/// <inheritdoc/>
@@ -268,12 +302,13 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
{
return Task.FromResult(Write(address, value));
}
/// <inheritdoc/>
protected override void Received(ByteBlock byteBlock, IRequestInfo requestInfo)
protected override async Task Received(SerialSession client, ReceivedDataEventArgs e)
{
try
{
var requestInfo = e.RequestInfo;
//接收外部报文
if (requestInfo is ModbusSerialServerMessage modbusServerMessage)
{
@@ -313,7 +348,7 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
if (WriteData != null)
{
// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
if (result.IsSuccess)
@@ -350,7 +385,7 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
if (WriteData != null)
{
if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
if (result.IsSuccess)
@@ -409,13 +444,9 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
private void Init(ModbusAddress mAddress)
{
if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128);
if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128);
if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128);
if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128);
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
}
}

View File

@@ -57,7 +57,7 @@ public class ModbusSerialServerDataHandleAdapter : ReadWriteDevicesTcpDataHandle
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}

View File

@@ -30,14 +30,11 @@ public class ModbusSerialServerMessage : MessageBase, IMessage
public override int HeadBytesLength => -1;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] head)
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
}
/// <inheritdoc/>
protected override void SendBytesThen()
{
}
}

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;

View File

@@ -23,10 +23,10 @@ public class ModbusTcpMessage : MessageBase, IMessage
/// </summary>
public bool IsCheckMessageId { get; set; } = false;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] head)
public override bool CheckHeadBytes(byte[] heads)
{
if (head == null || head.Length <= 0) return false;
HeadBytes = head;
if (heads == null || heads.Length <= 0) return false;
HeadBytes = heads;
int num = (HeadBytes[4] * 256) + HeadBytes[5];
BodyLength = num;

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;
@@ -85,15 +84,6 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
return new OperResult<byte[]>(ex);
}
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="client"></param>
/// <param name="e"></param>
protected override void Connecting(SocketClient client, ConnectingEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在连接");
}
/// <inheritdoc/>
public override void SetDataAdapter(object socketClient = null)
@@ -196,7 +186,7 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
var item = commandResult.Content;
if (FrameTime != 0)
Thread.Sleep(FrameTime);
var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true });
var WaitingClientEx = client.CreateWaitingClient(new() { });
var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
return (MessageBase)result.RequestInfo;
}
@@ -223,7 +213,7 @@ public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
var item = commandResult.Content;
await Task.Delay(FrameTime, cancellationToken);
var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true });
var WaitingClientEx = client.CreateWaitingClient(new() { });
var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
return (MessageBase)result.RequestInfo;
}

View File

@@ -11,7 +11,6 @@
#endregion
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using ThingsGateway.Foundation.Extension.Bool;
@@ -26,7 +25,7 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
/// <summary>
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
/// </summary>
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SocketClient, OperResult> WriteData;
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SocketClient, Task<OperResult>> WriteData;
/// <summary>
/// 继电器
@@ -105,62 +104,75 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
}
EasyLock easyLock = new();
/// <inheritdoc/>
public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
{
ModbusAddress mAddress;
try
{
mAddress = ModbusAddress.ParseFrom(address, Station);
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
easyLock.Wait();
ModbusAddress mAddress;
try
{
return new OperResult<byte[]>("地址错误");
mAddress = ModbusAddress.ParseFrom(address, Station);
}
Init(mAddress);
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
{
return new OperResult<byte[]>("地址错误");
}
Init(mAddress);
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
switch (mAddress.ReadFunction)
{
case 1:
byte[] bytes0 = new byte[len];
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Read(bytes0);
return OperResult.CreateSuccessResult(bytes0);
case 2:
byte[] bytes1 = new byte[len];
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Read(bytes1);
return OperResult.CreateSuccessResult(bytes1);
case 3:
byte[] bytes3 = new byte[len];
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Read(bytes3);
return OperResult.CreateSuccessResult(bytes3);
case 4:
byte[] bytes4 = new byte[len];
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Read(bytes4);
return OperResult.CreateSuccessResult(bytes4);
}
return new OperResult<byte[]>("功能码错误");
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength;
switch (mAddress.ReadFunction)
finally
{
case 1:
byte[] bytes0 = new byte[len];
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Read(bytes0);
return OperResult.CreateSuccessResult(bytes0);
case 2:
byte[] bytes1 = new byte[len];
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Read(bytes1);
return OperResult.CreateSuccessResult(bytes1);
case 3:
byte[] bytes3 = new byte[len];
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Read(bytes3);
return OperResult.CreateSuccessResult(bytes3);
case 4:
byte[] bytes4 = new byte[len];
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Read(bytes4);
return OperResult.CreateSuccessResult(bytes4);
easyLock.Release();
}
return new OperResult<byte[]>("功能码错误");
}
/// <inheritdoc/>
@@ -194,84 +206,104 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
/// <inheritdoc/>
public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
{
ModbusAddress mAddress;
try
{
mAddress = ModbusAddress.ParseFrom(address, Station);
}
catch (Exception ex)
{
return new OperResult(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
easyLock.Wait();
ModbusAddress mAddress;
try
{
return new OperResult("地址错误");
mAddress = ModbusAddress.ParseFrom(address, Station);
}
Init(mAddress);
catch (Exception ex)
{
return new OperResult(ex);
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
{
return new OperResult("地址错误");
}
Init(mAddress);
}
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
{
case 3:
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
case 4:
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
}
return new OperResult("功能码错误");
}
var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station];
var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
finally
{
case 3:
ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer03ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
case 4:
ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength;
ModbusServer04ByteBlock.Write(value);
return OperResult.CreateSuccessResult();
easyLock.Release();
}
return new OperResult("功能码错误");
}
/// <inheritdoc/>
public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
{
ModbusAddress mAddress;
try
{
mAddress = ModbusAddress.ParseFrom(address, Station);
}
catch (Exception ex)
{
return (new OperResult(ex));
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
easyLock.Wait();
ModbusAddress mAddress;
try
{
return (new OperResult("地址错误"));
mAddress = ModbusAddress.ParseFrom(address, Station);
}
Init(mAddress);
catch (Exception ex)
{
return (new OperResult(ex));
}
if (MulStation)
{
Init(mAddress);
}
else
{
if (Station != mAddress.Station)
{
return (new OperResult("地址错误"));
}
Init(mAddress);
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
{
case 1:
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
case 2:
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
}
return new OperResult("功能码错误");
}
var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station];
var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station];
switch (mAddress.ReadFunction)
finally
{
case 1:
ModbusServer01ByteBlock.Pos = mAddress.AddressStart;
ModbusServer01ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
case 2:
ModbusServer02ByteBlock.Pos = mAddress.AddressStart;
ModbusServer02ByteBlock.Write(value.BoolArrayToByte());
return (OperResult.CreateSuccessResult());
easyLock.Release();
}
return new OperResult("功能码错误");
}
/// <inheritdoc/>
@@ -285,12 +317,13 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
{
return Task.FromResult(Write(address, value));
}
/// <inheritdoc/>
protected override void Received(SocketClient client, IRequestInfo requestInfo)
protected override async Task Received(SocketClient client, ReceivedDataEventArgs e)
{
try
{
var requestInfo = e.RequestInfo;
//接收外部报文
if (requestInfo is ModbusTcpServerMessage modbusServerMessage)
{
@@ -331,7 +364,7 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
if (WriteData != null)
{
// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
if (result.IsSuccess)
@@ -368,7 +401,7 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
if (WriteData != null)
{
if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
if ((await WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
{
var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
if (result.IsSuccess)
@@ -429,13 +462,9 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
private void Init(ModbusAddress mAddress)
{
if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128);
if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128);
if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128);
if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128);
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
}
}

View File

@@ -57,7 +57,7 @@ public class ModbusTcpServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAda
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex.Message);
return new OperResult<byte[]>(ex);
}
}

View File

@@ -29,10 +29,10 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
/// <inheritdoc/>
public override int HeadBytesLength => 6;
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] head)
public override bool CheckHeadBytes(byte[] heads)
{
if (head == null || head.Length != 6) return false;
HeadBytes = head;
if (heads == null || heads.Length != 6) return false;
HeadBytes = heads;
int num = (HeadBytes[4] * 256) + HeadBytes[5];
BodyLength = num;

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.ComponentModel;
namespace ThingsGateway.Foundation.Adapter.Modbus;

View File

@@ -10,8 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Extension.String;

View File

@@ -406,7 +406,7 @@
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Received(ThingsGateway.Foundation.Sockets.SocketClient,ThingsGateway.Foundation.IRequestInfo)">
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Received(ThingsGateway.Foundation.Sockets.SocketClient,ThingsGateway.Foundation.Core.IRequestInfo)">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter">
@@ -598,7 +598,7 @@
PackHelper
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.PackHelper.ModbusLoadSourceRead``2(ThingsGateway.Foundation.IReadWrite,System.Collections.Generic.List{``1},System.Int32)">
<member name="M:ThingsGateway.Foundation.Adapter.Modbus.PackHelper.ModbusLoadSourceRead``2(ThingsGateway.Foundation.Core.IReadWrite,System.Collections.Generic.List{``1},System.Int32)">
<summary>
打包变量,添加到<see href="deviceVariableSourceReads"></see>
</summary>

View File

@@ -176,7 +176,7 @@ internal class OpcServer : IDisposable
{
status = (OPCSERVERSTATUS)o;
serverStatus = new();
serverStatus.Version = status.wMajorVersion.ToString() + "." + status.wMinorVersion.ToString() + "." + status.wBuildNumber.ToString();
serverStatus.Version = $"{status.wMajorVersion.ToString()}.{status.wMinorVersion.ToString()}.{status.wBuildNumber.ToString()}";
serverStatus.ServerState = status.dwServerState;
serverStatus.StartTime = Comn.Convert.FileTimeToDateTime(status.ftStartTime);
serverStatus.CurrentTime = Comn.Convert.FileTimeToDateTime(status.ftCurrentTime);

View File

@@ -1,3 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>

View File

@@ -1,579 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>ThingsGateway.Foundation.Adapter.OPCDA</name>
</assembly>
<members>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.CollectionExtensions.RemoveWhere``1(System.Collections.Generic.ICollection{``0},System.Func{``0,System.Boolean})">
<summary>
移除符合条件的元素
</summary>
<typeparam name="T"></typeparam>
<param name="this"></param>
<param name="where"></param>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.LOCALE_SYSTEM_DEFAULT">
<summary>
The WIN32 system default locale.
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.LOCALE_USER_DEFAULT">
<summary>
The WIN32 user default locale.
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.CreateInstance(System.Guid,System.String)">
<summary>
创建一个COM服务器的实例。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.GetSystemMessage(System.Int32)">
<summary>
指定错误消息文本检索系统。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.InitializeSecurity">
<summary>
初始化COM安全。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.ReadClasses(ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCEnumGUID)">
<summary>
从枚举器读取guid。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.ReadClasses(ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumGUID)">
<summary>
从枚举器读取guid。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.RealseComServer(System.Object)">
<summary>
释放 COM 对象
</summary>
<param name="m_server"></param>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCDA.Comn.Convert.FILETIME_BaseTime">
<summary>
windows的filetime是从1601-1-1 00:00:00开始的datetime是从1-1-1 00:00:00开始的
datetime和filetime的滴答单位都是100ns100纳秒千万分之一秒所以转换时只需要考虑开始时间即可
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OnDataChangedHandler">
<summary>
值变化
</summary>
<param name="opcItems"></param>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OnReadCompletedHandler">
<summary>
读取
</summary>
<param name="opcItems"></param>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OnWriteCompletedHandler">
<summary>
写入
</summary>
<param name="opcItems"></param>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult">
<summary>
返回结果
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.Name">
<summary>
ID
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.Quality">
<summary>
Quality
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.TimeStamp">
<summary>
TimeStamp
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.Value">
<summary>
Value
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcGroup.InitIoInterfaces(System.Object)">
<summary>
建立连接
</summary>
<param name="handle"></param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcGroup.ReadAsync">
<summary>
组读取
</summary>
<exception cref="T:System.Runtime.InteropServices.ExternalException"></exception>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem">
<summary>
OpcItem
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.#ctor(System.String)">
<summary>
OpcItem
</summary>
<param name="itemId"></param>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.AccessPath">
<summary>
AccessPath
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.Blob">
<summary>
Blob
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.BlobSize">
<summary>
BlobSize
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.ClientHandle">
<summary>
ClientHandle
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.IsActive">
<summary>
active(1) or not(0)
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.ItemID">
<summary>
数据项在opc server的完全名称
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.Quality">
<summary>
Quality
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.RunTimeDataType">
<summary>
RunTimeDataType
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.ServerHandle">
<summary>
ServerHandle
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.TimeStamp">
<summary>
TimeStamp
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.Value">
<summary>
Value
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcServer.AddGroup(System.String,System.Boolean,System.Int32,System.Single)">
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcServer.Browse(System.String)">
<summary>
获取节点
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcServer.GetServerStatus">
<summary>
服务器状态
</summary>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus">
<summary>
ServerStatus
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.CurrentTime">
<summary>
CurrentTime
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.LastUpdateTime">
<summary>
LastUpdateTime
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.ServerState">
<summary>
ServerState
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.StartTime">
<summary>
StartTime
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.VendorInfo">
<summary>
VendorInfo
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.Version">
<summary>
Version
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Discovery.OpcDiscovery">
<summary>
OpcDiscovery
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Discovery.OpcDiscovery.GetOpcServer(System.String,System.String)">
<summary>
GetOpcServer
</summary>
<param name="serverName"></param>
<param name="host"></param>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IConnectionPoint">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IConnectionPointContainer">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumConnectionPoints">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumConnections">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumGUID">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumString">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumUnknown">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCCommon">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCEnumGUID">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServerList">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServerList2">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCShutdown">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CONNECTDATA">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSEDIRECTION">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSEFILTER">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSETYPE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCDATASOURCE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCENUMSCOPE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCEUTYPE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCNAMESPACETYPE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCSERVERSTATE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_OPCDAServer10">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_OPCDAServer20">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_OPCDAServer30">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_XMLDAServer10">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumOPCItemAttributes">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCAsyncIO">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCAsyncIO2">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCAsyncIO3">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCBrowse">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCBrowseServerAddressSpace">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCDataCallback">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCGroupStateMgt">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCGroupStateMgt2">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemDeadbandMgt">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemIO">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemMgt">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemProperties">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemSamplingMgt">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCPublicGroupStateMgt">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServer">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServerPublicGroups">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCSyncIO">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCSyncIO2">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSEELEMENT">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCGROUPHEADER">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCGROUPHEADERWRITE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMATTRIBUTES">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMDEF">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMHEADER1">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMHEADER2">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMHEADERWRITE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMPROPERTIES">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMPROPERTY">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMRESULT">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMSTATE">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMVQT">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCSERVERSTATUS">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.Constants">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.Qualities">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.Properties">
<exclude />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.DataChangedEventHandler">
<summary>
订阅变化项
</summary>
<param name="values"></param>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient">
<summary>
OPCDAClient
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ItemDicts">
<summary>
当前保存的需订阅列表
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.#ctor(ThingsGateway.Foundation.ILog)">
<summary>
<inheritdoc/>
</summary>
<param name="logger"></param>
</member>
<member name="E:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.DataChangedHandler">
<summary>
数据变化事件
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.IsConnected">
<summary>
是否连接成功
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.OPCNode">
<summary>
当前配置
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.AddItems(System.Collections.Generic.Dictionary{System.String,System.Collections.Generic.List{ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem}})">
<summary>
添加节点,需要在连接成功后执行
</summary>
<param name="items">组名称/变量节点,注意每次添加的组名称不能相同</param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.AddItemsWithSave(System.Collections.Generic.List{System.String})">
<summary>
设置节点并保存,每次重连会自动添加节点
</summary>
<param name="items"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Connect">
<summary>
连接服务器
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Disconnect">
<summary>
断开连接
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.GetBrowseElements(System.String)">
<summary>
浏览节点
</summary>
<param name="itemId"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.GetServerStatus">
<summary>
获取服务状态
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Init(ThingsGateway.Foundation.Adapter.OPCDA.OPCNode)">
<summary>
初始化设置
</summary>
<param name="node"></param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ReadItemsWithGroup(System.String)">
<summary>
按OPC组读取组内变量结果会在订阅事件中返回
</summary>
<param name="groupName">组名称值为null时读取全部组</param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.RemoveItems(System.Collections.Generic.List{System.String})">
<summary>
移除节点
</summary>
<param name="items"></param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ToString">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.WriteItem(System.Collections.Generic.Dictionary{System.String,Newtonsoft.Json.Linq.JToken})">
<summary>
批量写入值
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Dispose(System.Boolean)">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode">
<summary>
OPCDA连接配置项
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.ActiveSubscribe">
<summary>
是否订阅
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.CheckRate">
<summary>
内部检测重连间隔/min
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.DeadBand">
<summary>
死区
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.GroupSize">
<summary>
分组大小
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.OPCIP">
<summary>
OPCIP
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.OPCName">
<summary>
OPCNAME
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.UpdateRate">
<summary>
订阅间隔
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.ToString">
<summary>
<inheritdoc/>
</summary>
<returns></returns>
</member>
</members>
</doc>

View File

@@ -1,4 +1,4 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
@@ -70,6 +70,11 @@ public class OPCNode
/// </summary>
[Description("安全策略")]
public bool IsUseSecurity { get; set; } = false;
/// <summary>
/// 加载服务端数据类型
/// </summary>
[Description("加载服务端数据类型")]
public bool LoadType { get; set; } = true;
/// <inheritdoc/>
public override string ToString()
{

View File

@@ -1,4 +1,4 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
@@ -17,22 +17,23 @@ using Opc.Ua.Client;
using Opc.Ua.Client.ComplexTypes;
using Opc.Ua.Configuration;
//修改自https://github.com/dathlin/OpcUaHelper 与OPC基金会net库
namespace ThingsGateway.Foundation.Adapter.OPCUA;
/// <summary>
/// 订阅委托
/// </summary>
/// <param name="value"></param>
public delegate void DataChangedEventHandler((VariableNode variableNode, DataValue dataValue, JToken jToken) value);
/// <summary>
/// OPCUAClient
/// </summary>
public class OPCUAClient : IDisposable
{
#region
/// <summary>
/// 当前配置
/// </summary>
@@ -46,32 +47,37 @@ public class OPCUAClient : IDisposable
/// <summary>
/// 当前保存的变量名称列表
/// </summary>
public List<string> Variables = new();
private readonly Action<byte, object, string, Exception> _logAction;
public List<List<string>> Variables = new();
/// <summary>
/// 当前的变量名称/OPC变量节点
/// </summary>
private readonly Dictionary<string, VariableNode> _variableDicts = new();
private readonly object checkLock = new();
/// <summary>
/// 当前的订阅组,组名称/组
/// </summary>
private readonly Dictionary<string, Subscription> dic_subscriptions = new();
private readonly ApplicationInstance m_application = new();
private readonly ApplicationConfiguration m_configuration;
private SessionReconnectHandler m_reConnectHandler;
private EventHandler m_ReconnectComplete;
private EventHandler m_ReconnectStarting;
private EventHandler<KeepAliveEventArgs> m_KeepAliveComplete;
private EventHandler<bool> m_ConnectComplete;
private EventHandler<OpcUaStatusEventArgs> m_OpcStatusChange;
private ISession m_session;
/// <summary>
/// 默认的构造函数实例化一个新的OPC UA类
/// </summary>
public OPCUAClient(Action<byte, object, string, Exception> log)
public OPCUAClient()
{
_logAction = log;
var certificateValidator = new CertificateValidator();
certificateValidator.CertificateValidation += CertificateValidation;
@@ -90,7 +96,6 @@ public class OPCUAClient : IDisposable
MaxMessageQueueSize = 1000000,
MaxNotificationQueueSize = 1000000,
MaxPublishRequestCount = 10000000,
},
SecurityConfiguration = new SecurityConfiguration
@@ -133,8 +138,6 @@ public class OPCUAClient : IDisposable
StoreType = CertificateStoreType.Directory,
StorePath = AppContext.BaseDirectory + @"OPCUAClientCertificate\pki\trustedUser",
}
},
TransportQuotas = new TransportQuotas
@@ -160,8 +163,6 @@ public class OPCUAClient : IDisposable
m_configuration.Validate(ApplicationType.Client);
m_application.ApplicationConfiguration = m_configuration;
}
/// <summary>
@@ -188,6 +189,52 @@ public class OPCUAClient : IDisposable
/// SessionReconnectHandler
/// </summary>
public SessionReconnectHandler ReConnectHandler => m_reConnectHandler;
/// <summary>
/// Raised when a good keep alive from the server arrives.
/// </summary>
public event EventHandler<KeepAliveEventArgs> KeepAliveComplete
{
add { m_KeepAliveComplete += value; }
remove { m_KeepAliveComplete -= value; }
}
/// <summary>
/// Raised when a reconnect operation starts.
/// </summary>
public event EventHandler ReconnectStarting
{
add { m_ReconnectStarting += value; }
remove { m_ReconnectStarting -= value; }
}
/// <summary>
/// Raised when a reconnect operation completes.
/// </summary>
public event EventHandler ReconnectComplete
{
add { m_ReconnectComplete += value; }
remove { m_ReconnectComplete -= value; }
}
/// <summary>
/// Raised after successfully connecting to or disconnecing from a server.
/// </summary>
public event EventHandler<bool> ConnectComplete
{
add { m_ConnectComplete += value; }
remove { m_ConnectComplete -= value; }
}
/// <summary>
/// Raised after the client status change
/// </summary>
public event EventHandler<OpcUaStatusEventArgs> OpcStatusChange
{
add { m_OpcStatusChange += value; }
remove { m_OpcStatusChange -= value; }
}
/// <summary>
/// 当前活动会话。
/// </summary>
@@ -200,7 +247,7 @@ public class OPCUAClient : IDisposable
/// <summary>
/// 新增订阅需要指定订阅组名称订阅的tag名数组
/// </summary>
public async Task AddSubscriptionAsync(string subscriptionName, string[] items)
public async Task AddSubscriptionAsync(string subscriptionName, string[] items, bool loadType = true)
{
Subscription m_subscription = new(m_session.DefaultSubscription)
{
@@ -213,14 +260,14 @@ public class OPCUAClient : IDisposable
DisplayName = subscriptionName
};
List<MonitoredItem> monitoredItems = new();
var variableNodes = loadType ? await ReadNodesAsync(items) : null;
for (int i = 0; i < items.Length; i++)
{
try
{
var variableNode = await ReadNodeAsync(items[i], false);
var item = new MonitoredItem
{
StartNodeId = variableNode.NodeId,
StartNodeId = loadType ? variableNodes[i].NodeId : items[i],
AttributeId = Attributes.Value,
DisplayName = items[i],
Filter = OPCNode.DeadBand == 0 ? null : new DataChangeFilter() { DeadbandValue = OPCNode.DeadBand, DeadbandType = (int)DeadbandType.Absolute, Trigger = DataChangeTrigger.StatusValue },
@@ -231,7 +278,7 @@ public class OPCUAClient : IDisposable
}
catch (Exception ex)
{
_logAction?.Invoke(3, this, $"初始化{items[i]}变量订阅失败", ex);
UpdateStatus(3, DateTime.Now, $"初始化{items[i]}变量订阅失败,错误原因:{ex}");
}
}
m_subscription.AddItems(monitoredItems);
@@ -247,9 +294,9 @@ public class OPCUAClient : IDisposable
var isError = m_subscription.MonitoredItems.Any(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode));
if (isError)
{
_logAction?.Invoke(3, this, $"创建以下变量订阅失败:{Environment.NewLine}{m_subscription.MonitoredItems.Where(
UpdateStatus(3, DateTime.Now, $"创建以下变量订阅失败:{Environment.NewLine}{m_subscription.MonitoredItems.Where(
a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode))
.Select(a => a.StartNodeId.ToString() + "" + a.Status.Error.ToString()).ToJsonString()}", null);
.Select(a => $"{a.StartNodeId.ToString()}{a.Status.Error.ToString()}").ToJsonString()}");
}
lock (dic_subscriptions)
@@ -281,7 +328,6 @@ public class OPCUAClient : IDisposable
item.Value.Delete(true);
m_session.RemoveSubscription(item.Value);
try { item.Value.Dispose(); } catch { }
}
dic_subscriptions.Clear();
}
@@ -304,39 +350,40 @@ public class OPCUAClient : IDisposable
dic_subscriptions.RemoveWhere(a => a.Key == subscriptionName);
}
}
}
private async void Callback(MonitoredItem monitoreditem, MonitoredItemNotificationEventArgs monitoredItemNotificationEventArgs)
private void Callback(MonitoredItem monitoreditem, MonitoredItemNotificationEventArgs monitoredItemNotificationEventArgs)
{
try
{
var variableNode = await ReadNodeAsync(monitoreditem.StartNodeId.ToString(), false);
foreach (var value in monitoreditem.DequeueValues())
if (m_session != null)
{
if (value.Value != null)
var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false);
foreach (var value in monitoreditem.DequeueValues())
{
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
if (data == null && value.Value != null)
if (value.Value != null)
{
_logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}转换出错原始值String为{value.Value}", null);
var data1 = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
if (data == null && value.Value != null)
{
UpdateStatus(3, DateTime.Now, $"{monitoreditem.StartNodeId}转换出错原始值String为{value.Value}");
var data1 = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
}
DataChangedHandler?.Invoke((variableNode, value, data));
}
else
{
var data = JValue.CreateNull();
DataChangedHandler?.Invoke((variableNode, value, data));
}
DataChangedHandler?.Invoke((variableNode, value, data));
}
else
{
var data = JValue.CreateNull();
DataChangedHandler?.Invoke((variableNode, value, data));
}
}
}
catch (Exception ex)
{
_logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}订阅处理错误", ex);
UpdateStatus(3, DateTime.Now, $"{monitoreditem.StartNodeId}订阅处理错误,错误原因:" + ex);
}
}
#endregion
@@ -462,17 +509,16 @@ public class OPCUAClient : IDisposable
#endregion
#region
private ComplexTypeSystem typeSystem;
/// <summary>
/// 连接到服务器
/// </summary>
public async Task ConnectAsync()
public async Task ConnectAsync(CancellationToken cancellationToken)
{
await ConnectAsync(OPCNode.OPCUrl);
_logAction?.Invoke(1, this, $"连接成功", null);
await ConnectAsync(OPCNode.OPCUrl, cancellationToken);
}
/// <summary>
@@ -484,15 +530,15 @@ public class OPCUAClient : IDisposable
// disconnect any existing session.
if (m_session != null)
{
_logAction?.Invoke(1, this, $"主动断开连接", null);
m_session = null;
}
}
/// <summary>
/// Creates a new session.
/// </summary>
/// <returns>The new session object.</returns>
private async Task<ISession> ConnectAsync(string serverUrl)
private async Task<ISession> ConnectAsync(string serverUrl, CancellationToken cancellationToken)
{
PrivateDisconnect();
@@ -501,6 +547,7 @@ public class OPCUAClient : IDisposable
throw new ArgumentNullException("未初始化配置");
}
var useSecurity = OPCNode?.IsUseSecurity ?? true;
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(m_configuration, serverUrl, useSecurity, 10000);
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
ConfiguredEndpoint endpoint = new(null, endpointDescription, endpointConfiguration);
@@ -516,28 +563,41 @@ public class OPCUAClient : IDisposable
//创建本地证书
await m_application.CheckApplicationInstanceCertificate(true, 0, 1200);
m_session = await Opc.Ua.Client.Session.Create(
m_configuration,
endpoint,
false,
OPCNode.CheckDomain,
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
60000,
userIdentity,
Array.Empty<string>());
m_configuration,
endpoint,
false,
OPCNode.CheckDomain,
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
60000,
userIdentity,
Array.Empty<string>(), cancellationToken
).ConfigureAwait(false);
typeSystem = new ComplexTypeSystem(m_session);
m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;
m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
// raise an event.
DoConnectComplete(true);
UpdateStatus(2, DateTime.UtcNow, "Connected");
//如果是订阅模式,连接时添加订阅组
if (OPCNode.ActiveSubscribe)
await AddSubscriptionAsync(Guid.NewGuid().ToString(), Variables.ToArray());
{
foreach (var item in Variables)
{
await AddSubscriptionAsync(Guid.NewGuid().ToString(), item.ToArray(), OPCNode.LoadType);
}
}
return m_session;
}
private void PrivateDisconnect()
{
bool state = m_session?.Connected == true;
if (m_reConnectHandler != null)
{
try { m_reConnectHandler.Dispose(); } catch { }
@@ -549,8 +609,14 @@ public class OPCUAClient : IDisposable
m_session.Close(10000);
}
if (state)
{
UpdateStatus(2, DateTime.UtcNow, "Disconnected");
DoConnectComplete(false);
}
}
#endregion
#region /
@@ -593,7 +659,6 @@ public class OPCUAClient : IDisposable
valuesToWrite.Add(valueToWrite);
}
var result = await m_session.WriteAsync(
requestHeader: null,
nodesToWrite: valuesToWrite, cancellationToken);
@@ -601,7 +666,6 @@ public class OPCUAClient : IDisposable
ClientBase.ValidateResponse(result.Results, valuesToWrite);
ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, valuesToWrite);
var keys = writeInfoLists.Keys.ToList();
for (int i = 0; i < keys.Count; i++)
{
@@ -624,7 +688,6 @@ public class OPCUAClient : IDisposable
}
return results;
}
}
/// <summary>
@@ -680,15 +743,61 @@ public class OPCUAClient : IDisposable
return value;
}
}
NodeId nodeToRead = new(nodeIdStr);
var node = (VariableNode)await m_session.ReadNodeAsync(nodeToRead, cancellationToken);
await typeSystem.LoadType(node.DataType, true, true);
var node = (VariableNode)await m_session.ReadNodeAsync(nodeToRead, NodeClass.Variable, false, cancellationToken);
if (OPCNode.LoadType)
await typeSystem.LoadType(node.DataType).ConfigureAwait(false);
_variableDicts.AddOrUpdate(nodeIdStr, node);
return node;
}
#endregion
/// <summary>
/// 从服务器或缓存读取节点
/// </summary>
private VariableNode ReadNode(string nodeIdStr, bool isOnlyServer = true)
{
if (!isOnlyServer)
{
if (_variableDicts.TryGetValue(nodeIdStr, out var value))
{
return value;
}
}
NodeId nodeToRead = new(nodeIdStr);
var node = (VariableNode)m_session.ReadNode(nodeToRead, NodeClass.Variable, false);
_variableDicts.AddOrUpdate(nodeIdStr, node);
return node;
}
/// <summary>
/// 从服务器读取节点
/// </summary>
private async Task<List<Node>> ReadNodesAsync(string[] nodeIdStrs, CancellationToken cancellationToken = default)
{
List<NodeId> nodeIds = new List<NodeId>();
foreach (var item in nodeIdStrs)
{
NodeId nodeToRead = new(item);
nodeIds.Add(nodeToRead);
}
(IList<Node>, IList<ServiceResult>) nodes = await m_session.ReadNodesAsync(nodeIds, NodeClass.Variable, false, cancellationToken);
for (int i = 0; i < nodes.Item1.Count; i++)
{
if (StatusCode.IsGood(nodes.Item2[i].StatusCode))
{
var node = ((VariableNode)nodes.Item1[i]);
await typeSystem.LoadType(node.DataType).ConfigureAwait(false);
_variableDicts.AddOrUpdate(nodeIdStrs[i], node);
}
else
{
UpdateStatus(3, DateTime.Now, $"获取服务器节点信息失败{nodes.Item2[i]}");
}
}
return nodes.Item1.ToList();
}
#endregion
#region
@@ -754,7 +863,6 @@ public class OPCUAClient : IDisposable
ResultMask = (uint)BrowseResultMask.All
};
nodesToBrowse.Add(nodeToBrowse);
}
return await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, cancellationToken);
@@ -917,11 +1025,9 @@ public class OPCUAClient : IDisposable
return nodeAttribute.ToArray();
}
#endregion
/// <inheritdoc/>
public void Dispose()
{
@@ -940,7 +1046,6 @@ public class OPCUAClient : IDisposable
throw new Exception(string.Format("验证证书失败,错误代码:{0}: {1}", eventArgs.Error.Code, eventArgs.Error.AdditionalInfo));
}
private async Task<Dictionary<string, List<OPCNodeAttribute>>> ReadNoteAttributeAsync(BrowseDescriptionCollection nodesToBrowse, ReadValueIdCollection nodesToRead, CancellationToken cancellationToken)
{
int startOfProperties = nodesToRead.Count;
@@ -1017,7 +1122,6 @@ public class OPCUAClient : IDisposable
}
}
if (nodeAttributes.ContainsKey(nodeToRead.NodeId.ToString()))
{
nodeAttributes[nodeToRead.NodeId.ToString()].Add(item);
@@ -1035,21 +1139,47 @@ public class OPCUAClient : IDisposable
/// </summary>
private void Server_ReconnectComplete(object sender, EventArgs e)
{
if (!Object.ReferenceEquals(sender, m_reConnectHandler))
try
{
return;
if (!Object.ReferenceEquals(sender, m_reConnectHandler))
{
return;
}
m_session = m_reConnectHandler.Session;
m_reConnectHandler.Dispose();
m_reConnectHandler = null;
// raise any additional notifications.
m_ReconnectComplete?.Invoke(this, e);
}
catch (Exception)
{
throw;
}
}
m_session = m_reConnectHandler.Session;
m_reConnectHandler = null;
/// <summary>
/// Report the client status
/// </summary>
/// <param name="logLevel">Whether the status represents an error. </param>
/// <param name="time">The time associated with the status.</param>
/// <param name="status">The status message.</param>
/// <param name="args">Arguments used to format the status message.</param>
private void UpdateStatus(int logLevel, DateTime time, string status, params object[] args)
{
m_OpcStatusChange?.Invoke(this, new OpcUaStatusEventArgs()
{
LogLevel = logLevel,
Time = time.ToLocalTime(),
Text = String.Format(status, args),
});
}
private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
{
lock (checkLock)
{
if (!Object.ReferenceEquals(session, m_session))
{
return;
@@ -1057,22 +1187,39 @@ public class OPCUAClient : IDisposable
if (ServiceResult.IsBad(e.Status))
{
_logAction?.Invoke(3, this, $"心跳检测错误:{e.Status}", null);
if (m_session.KeepAliveInterval <= 0)
{
UpdateStatus(3, e.CurrentTime, "Communication Error ({0})", e.Status);
return;
}
UpdateStatus(3, e.CurrentTime, "Reconnecting in {0}s", m_session.KeepAliveInterval / 1000);
if (m_reConnectHandler == null)
{
m_ReconnectStarting?.Invoke(this, e);
m_reConnectHandler = new SessionReconnectHandler();
m_reConnectHandler.BeginReconnect(m_session, m_session.KeepAliveInterval, Server_ReconnectComplete);
}
return;
}
// update status.
UpdateStatus(0, e.CurrentTime, "Session_KeepAlive Connected [{0}]", session.Endpoint.EndpointUrl);
// raise any additional notifications.
m_KeepAliveComplete?.Invoke(this, e);
}
}
/// <summary>
/// Raises the connect complete event on the main GUI thread.
/// </summary>
private void DoConnectComplete(bool state)
{
m_ConnectComplete?.Invoke(this, state);
}
#endregion
}

View File

@@ -1,4 +1,4 @@
#region copyright
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
@@ -13,6 +13,33 @@
using Opc.Ua;
namespace ThingsGateway.Foundation.Adapter.OPCUA;
/// <summary>
/// OPC UA的状态更新消息
/// </summary>
public class OpcUaStatusEventArgs
{
/// <summary>
/// 日志等级,<br></br>
/// 更为详细的步骤型日志输出 Trace = 0,<br></br>
/// 调试信息日志Debug = 1,<br></br>
/// 消息类日志输出 Info = 2,<br></br>
/// 警告类日志输出 Warning = 3,<br></br>
/// 错误类日志输出 Error = 4,<br></br>
/// 不可控中断类日输出Critical = 5,
/// </summary>
public int LogLevel { get; set; }
/// <summary>
/// 时间
/// </summary>
public DateTime Time { get; set; }
/// <summary>
/// 文本
/// </summary>
public string Text { get; set; }
}
/// <summary>
/// 读取属性过程中用于描述的
/// </summary>
@@ -22,6 +49,7 @@ public class OPCNodeAttribute
/// 属性的名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 操作结果状态描述
/// </summary>
@@ -31,10 +59,9 @@ public class OPCNodeAttribute
/// 属性的类型描述
/// </summary>
public string Type { get; set; }
/// <summary>
/// 属性的值,如果读取错误,返回文本描述
/// </summary>
public object Value { get; set; }
}
}

View File

@@ -7,9 +7,8 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.372.56" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.372.56" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.372.76" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.372.76" />
</ItemGroup>
</Project>

View File

@@ -1,468 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>ThingsGateway.Foundation.Adapter.OPCUA</name>
</assembly>
<members>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.CollectionExtensions.RemoveWhere``1(System.Collections.Generic.ICollection{``0},System.Func{``0,System.Boolean})">
<summary>
移除符合条件的元素
</summary>
<typeparam name="T"></typeparam>
<param name="this"></param>
<param name="where"></param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.CollectionExtensions.SelectAsync``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,System.Threading.Tasks.Task{``1}})">
<summary>
异步Select
</summary>
<typeparam name="T"></typeparam>
<typeparam name="TResult"></typeparam>
<param name="source"></param>
<param name="selector"></param>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils">
<summary>
辅助类
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.Browse(Opc.Ua.Client.ISession,Opc.Ua.BrowseDescriptionCollection,System.Boolean)">
<summary>
Browses the address space and returns the references found.
</summary>
<param name="session">The session.</param>
<param name="nodesToBrowse">The set of browse operations to perform.</param>
<param name="throwOnError">if set to <c>true</c> a exception will be thrown on an error.</param>
<returns>
The references found. Null if an error occurred.
</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.PrepareBrowseNext(Opc.Ua.BrowseResultCollection)">
<summary>
Create the continuation point collection from the browse result
collection for the BrowseNext service.
</summary>
<param name="browseResultCollection">The browse result collection to use.</param>
<returns>The collection of continuation points for the BrowseNext service.</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.BrowseAsync(Opc.Ua.Client.ISession,Opc.Ua.BrowseDescriptionCollection,System.Boolean,System.Threading.CancellationToken)">
<summary>
浏览地址空间
</summary>
<param name="session"></param>
<param name="nodesToBrowse"></param>
<param name="throwOnError"></param>
<param name="cancellationToken"></param>
<returns></returns>
<exception cref="T:Opc.Ua.ServiceResultException"></exception>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.BrowseAsync(Opc.Ua.Client.ISession,Opc.Ua.BrowseDescription,System.Boolean,System.Threading.CancellationToken)">
<summary>
浏览地址空间
</summary>
<param name="session"></param>
<param name="nodeToBrowse"></param>
<param name="throwOnError"></param>
<param name="cancellationToken"></param>
<returns></returns>
<exception cref="T:Opc.Ua.ServiceResultException"></exception>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.BrowseSuperTypesAsync(Opc.Ua.Client.ISession,Opc.Ua.NodeId,System.Boolean)">
<summary>
浏览地址空间并返回指定类型的所有节点
</summary>
<param name="session"></param>
<param name="typeId"></param>
<param name="throwOnError"></param>
<returns></returns>
<exception cref="T:Opc.Ua.ServiceResultException"></exception>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.CollectFieldsForInstanceAsync(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.SimpleAttributeOperandCollection,System.Collections.Generic.List{Opc.Ua.NodeId})">
<summary>
Collects the fields for the instance.
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.CollectFieldsForType(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.SimpleAttributeOperandCollection,System.Collections.Generic.List{Opc.Ua.NodeId})">
<summary>
Collects the fields for the type.
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.ConstructEventAsync(Opc.Ua.Client.ISession,Opc.Ua.Client.MonitoredItem,Opc.Ua.EventFieldList,System.Collections.Generic.Dictionary{Opc.Ua.NodeId,System.Type},System.Collections.Generic.Dictionary{Opc.Ua.NodeId,Opc.Ua.NodeId})">
<summary>
Constructs an event object from a notification.
</summary>
<param name="session">The session.</param>
<param name="monitoredItem">The monitored item that produced the notification.</param>
<param name="notification">The notification.</param>
<param name="knownEventTypes">The known event types.</param>
<param name="eventTypeMappings">Mapping between event types and known event types.</param>
<returns>
The event object. Null if the notification is not a valid event type.
</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.DiscoverServers(Opc.Ua.ApplicationConfiguration)">
<summary>
Discovers the servers on the local machine.
</summary>
<param name="configuration">The configuration.</param>
<returns>A list of server urls.</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.FindEventType(Opc.Ua.Client.MonitoredItem,Opc.Ua.EventFieldList)">
<summary>
Finds the type of the event for the notification.
</summary>
<param name="monitoredItem">The monitored item.</param>
<param name="notification">The notification.</param>
<returns>The NodeId of the EventType.</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.GetAttributeDisplayText(Opc.Ua.Client.ISession,System.UInt32,Opc.Ua.Variant)">
<summary>
指定的属性的显示文本。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.SelectEndpoint(System.String,System.Boolean)">
<summary>
Finds the endpoint that best matches the current settings.
</summary>
<param name="discoveryUrl">The discovery URL.</param>
<param name="useSecurity">if set to <c>true</c> select an endpoint that uses security.</param>
<returns>The best available endpoint.</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.TranslateBrowsePaths(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.NamespaceTable,System.Threading.CancellationToken,System.String[])">
<summary>
返回一组相对路径的节点id
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.CollectFieldsAsync(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.QualifiedNameCollection,Opc.Ua.SimpleAttributeOperandCollection,System.Collections.Generic.List{Opc.Ua.NodeId},System.Collections.Generic.Dictionary{Opc.Ua.NodeId,Opc.Ua.QualifiedNameCollection})">
<summary>
Collects the fields for the instance node.
</summary>
<param name="session">The session.</param>
<param name="nodeId">The node id.</param>
<param name="parentPath">The parent path.</param>
<param name="fields">The event fields.</param>
<param name="fieldNodeIds">The node id for the declaration of the field.</param>
<param name="foundNodes">The table of found nodes.</param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.ContainsPath(Opc.Ua.SimpleAttributeOperandCollection,Opc.Ua.QualifiedNameCollection)">
<summary>
判断指定的select子句包含的浏览路径。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.GetAccessLevelDisplayText(System.Byte)">
<summary>
访问级别属性的显示文本。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.GetEventNotifierDisplayText(System.Byte)">
<summary>
事件通知属性的显示文本
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils">
<summary>
扩展方法
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.Decode(Opc.Ua.IServiceMessageContext,Opc.Ua.NodeId,Opc.Ua.BuiltInType,System.Int32,Newtonsoft.Json.Linq.JToken)">
<summary>
解析获取DataValue
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecoderObject(Opc.Ua.IServiceMessageContext,Opc.Ua.NodeId,Opc.Ua.BuiltInType,System.Int32,Newtonsoft.Json.Linq.JToken)">
<summary>
解析获取object
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecodeRawData(Opc.Ua.JsonDecoder,Opc.Ua.BuiltInType,System.Int32,System.String)">
<summary>
DecodeRawData
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.Encode(Opc.Ua.IServiceMessageContext,Opc.Ua.BuiltInType,System.Object)">
<summary>
OPCUAValue解析为Jtoken
</summary>
<param name="Context"></param>
<param name="type"></param>
<param name="value"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.CreateEncoder(Opc.Ua.IServiceMessageContext,System.IO.Stream,System.Boolean,System.Boolean,System.Boolean,System.Boolean)">
<summary>
CreateEncoder
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.CalculateActualValueRank(Newtonsoft.Json.Linq.JToken)">
<summary>
维度
</summary>
<param name="jToken"></param>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode">
<summary>
OPCUAClient配置项
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.OPCUrl">
<summary>
OPCUrl
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.UserName">
<summary>
登录账号
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.Password">
<summary>
登录密码
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.CheckDomain">
<summary>
检查域
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.UpdateRate">
<summary>
更新间隔
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.ActiveSubscribe">
<summary>
是否订阅
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.GroupSize">
<summary>
分组大小
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.DeadBand">
<summary>
死区
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.KeepAliveInterval">
<summary>
KeepAliveInterval/ms
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.IsUseSecurity">
<summary>
安全策略
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.ToString">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCUA.DataChangedEventHandler">
<summary>
订阅委托
</summary>
<param name="value"></param>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient">
<summary>
OPCUAClient
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.OPCNode">
<summary>
当前配置
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ProductUri">
<summary>
ProductUri
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Variables">
<summary>
当前保存的变量名称列表
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient._variableDicts">
<summary>
当前的变量名称/OPC变量节点
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.dic_subscriptions">
<summary>
当前的订阅组,组名称/组
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReConnectHandler">
<summary>
SessionReconnectHandler
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.#ctor(ThingsGateway.Foundation.ILog)">
<summary>
默认的构造函数实例化一个新的OPC UA类
</summary>
</member>
<member name="E:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.DataChangedHandler">
<summary>
订阅
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.AppConfig">
<summary>
配置信息
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Connected">
<summary>
连接状态
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.OPCUAName">
<summary>
OPCUAClient
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Session">
<summary>
当前活动会话。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.AddSubscriptionAsync(System.String,System.String[])">
<summary>
新增订阅需要指定订阅组名称订阅的tag名数组
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.RemoveAllSubscription">
<summary>
移除所有的订阅消息
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.RemoveSubscription(System.String)">
<summary>
移除订阅消息
</summary>
<param name="subscriptionName">组名称</param>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.BrowseNodeReferenceAsync(System.String)">
<summary>
浏览一个节点的引用
</summary>
<param name="tag">节点值</param>
<returns>引用节点描述</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.CallMethodByNodeId(System.String,System.String,System.Object[])">
<summary>
调用服务器的方法
</summary>
<param name="tagParent">方法的父节点tag</param>
<param name="tag">方法的节点tag</param>
<param name="args">传递的参数</param>
<returns>输出的结果值</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadHistoryRawDataValues(System.String,System.DateTime,System.DateTime,System.UInt32,System.Boolean,System.Threading.CancellationToken)">
<summary>
读取历史数据
</summary>
<param name="tag">节点的索引</param>
<param name="start">开始时间</param>
<param name="end">结束时间</param>
<param name="count">读取的个数</param>
<param name="containBound">是否包含边界</param>
<param name="cancellationToken">cancellationToken</param>
<returns>读取的数据列表</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ConnectAsync">
<summary>
连接到服务器
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Disconnect">
<summary>
断开连接。
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ConnectAsync(System.String)">
<summary>
Creates a new session.
</summary>
<returns>The new session object.</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadJTokenValueAsync(System.String[],System.Threading.CancellationToken)">
<summary>
从服务器读取值
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.WriteNodeAsync(System.Collections.Generic.Dictionary{System.String,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)">
<summary>
异步写opc标签
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadJTokenValueAsync(Opc.Ua.NodeId[],System.Threading.CancellationToken)">
<summary>
从服务器读取值
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNodeAsync(System.String,System.Boolean,System.Threading.CancellationToken)">
<summary>
从服务器或缓存读取节点
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNoteAttributeAsync(System.String,System.UInt32,System.Threading.CancellationToken)">
<summary>
读取一个节点的所有属性
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNoteAttributeAsync(System.Collections.Generic.List{System.String},System.Threading.CancellationToken)">
<summary>
读取节点的所有属性
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNoteAttributes(System.String)">
<summary>
读取一个节点的所有属性
</summary>
<param name="tag">节点信息</param>
<returns>节点的特性值</returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Dispose(System.Boolean)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Server_ReconnectComplete(System.Object,System.EventArgs)">
<summary>
连接处理器连接事件处理完成。
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute">
<summary>
读取属性过程中用于描述的
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.Name">
<summary>
属性的名称
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.StatusCode">
<summary>
操作结果状态描述
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.Type">
<summary>
属性的类型描述
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.Value">
<summary>
属性的值,如果读取错误,返回文本描述
</summary>
</member>
</members>
</doc>

View File

@@ -11,8 +11,10 @@
#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.Sockets;

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
using ThingsGateway.Foundation.Extension.String;
using ThingsGateway.Foundation.Extension;
namespace ThingsGateway.Foundation.Adapter.Siemens;
/// <summary>
@@ -54,7 +54,10 @@ public class SiemensAddress : DeviceAddressBase
/// DB块数据信息
/// </summary>
public ushort DbBlock { get; set; }
/// <summary>
/// IsWString默认是true如果不是WString,需要填写W=false;
/// </summary>
public bool IsWString { get; set; } = true;
/// <summary>
/// 获取起始地址
/// </summary>
@@ -103,127 +106,132 @@ public class SiemensAddress : DeviceAddressBase
public static SiemensAddress ParseFrom(string address)
{
SiemensAddress s7AddressData = new();
address = address.ToUpper();
address = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
string[] strArr = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
for (int index = 0; index < strArr.Length; ++index)
{
if (strArr[index].StartsWith("W="))
{
s7AddressData.IsWString = strArr[index].Substring(2).ToBoolean(true);
}
else if (!strArr[index].Contains("="))
{
s7AddressData.DbBlock = 0;
if (address.StartsWith("AI"))
{
s7AddressData.DataCode = (byte)S7Area.AI;
if (address.StartsWith("AIX") || address.StartsWith("AIB") || address.StartsWith("AIW") || address.StartsWith("AID"))
{
s7AddressData.Address = GetAddressStart(address.Substring(3)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(3));
}
else
{
s7AddressData.Address = GetAddressStart(address.Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(2));
}
}
else if (address.StartsWith("AQ"))
{
s7AddressData.DataCode = (byte)S7Area.AQ;
if (address.StartsWith("AQX") || address.StartsWith("AQB") || address.StartsWith("AQW") || address.StartsWith("AQD"))
{
s7AddressData.Address = GetAddressStart(address.Substring(3)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(3));
}
else
{
s7AddressData.Address = GetAddressStart(address.Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(2));
}
}
else if (address[0] == 'I')
{
s7AddressData.DataCode = (byte)S7Area.PE;
if (address.StartsWith("IX") || address.StartsWith("IB") || address.StartsWith("IW") || address.StartsWith("ID"))
{
s7AddressData.Address = GetAddressStart(address.Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(address.Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(1));
}
}
else if (address[0] == 'Q')
{
s7AddressData.DataCode = (byte)S7Area.PA;
if (address.StartsWith("QX") || address.StartsWith("QB") || address.StartsWith("QW") || address.StartsWith("QD"))
{
s7AddressData.Address = GetAddressStart(address.Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(address.Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(1));
}
}
else if (address[0] == 'M')
{
s7AddressData.DataCode = (byte)S7Area.MK;
if (address.StartsWith("MX") || address.StartsWith("MB") || address.StartsWith("MW") || address.StartsWith("MD"))
{
s7AddressData.Address = GetAddressStart(address.Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(address.Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(1));
}
}
else if (address[0] == 'D' || address.Substring(0, 2) == "DB")
{
s7AddressData.DataCode = (byte)S7Area.DB;
string[] strArray = address.Split('.');
s7AddressData.DbBlock = address[1] != 'B' ? Convert.ToUInt16(strArray[0].Substring(1)) : Convert.ToUInt16(strArray[0].Substring(2));
string address1 = address.Substring(address.IndexOf('.') + 1);
if (address1.StartsWith("DBX") || address1.StartsWith("DBB") || address1.StartsWith("DBW") || address1.StartsWith("DBD"))
{
address1 = address1.Substring(3);
}
s7AddressData.DbBlock = 0;
s7AddressData.Address = GetAddressStart(address1).ToString();
s7AddressData.BitCode = GetBitCode(address1);
}
else if (address[0] == 'T')
{
s7AddressData.DataCode = (byte)S7Area.TM;
s7AddressData.Address = GetAddressStart(address.Substring(1), true).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(1));
}
else if (address[0] == 'C')
{
s7AddressData.DataCode = (byte)S7Area.CT;
s7AddressData.Address = GetAddressStart(address.Substring(1), true).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(1));
}
else if (address[0] == 'V')
{
s7AddressData.DataCode = (byte)S7Area.DB;
s7AddressData.DbBlock = 1;
if (address.StartsWith("VB") || address.StartsWith("VW") || address.StartsWith("VD") || address.StartsWith("VX"))
{
s7AddressData.Address = GetAddressStart(address.Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(address.Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(address.Substring(1));
}
}
else
{
throw new Exception("解析错误,无相关变量类型");
}
if (strArr[index].StartsWith("AI"))
{
s7AddressData.DataCode = (byte)S7Area.AI;
if (strArr[index].StartsWith("AIX") || strArr[index].StartsWith("AIB") || strArr[index].StartsWith("AIW") || strArr[index].StartsWith("AID"))
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(3)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(3));
}
else
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2));
}
}
else if (strArr[index].StartsWith("AQ"))
{
s7AddressData.DataCode = (byte)S7Area.AQ;
if (strArr[index].StartsWith("AQX") || strArr[index].StartsWith("AQB") || strArr[index].StartsWith("AQW") || strArr[index].StartsWith("AQD"))
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(3)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(3));
}
else
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2));
}
}
else if (strArr[index][0] == 'I')
{
s7AddressData.DataCode = (byte)S7Area.PE;
if (strArr[index].StartsWith("IX") || strArr[index].StartsWith("IB") || strArr[index].StartsWith("IW") || strArr[index].StartsWith("ID"))
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1));
}
}
else if (strArr[index][0] == 'Q')
{
s7AddressData.DataCode = (byte)S7Area.PA;
if (strArr[index].StartsWith("QX") || strArr[index].StartsWith("QB") || strArr[index].StartsWith("QW") || strArr[index].StartsWith("QD"))
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1));
}
}
else if (strArr[index][0] == 'M')
{
s7AddressData.DataCode = (byte)S7Area.MK;
if (strArr[index].StartsWith("MX") || strArr[index].StartsWith("MB") || strArr[index].StartsWith("MW") || strArr[index].StartsWith("MD"))
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1));
}
}
else if (strArr[index][0] == 'D' || strArr[index].Substring(0, 2) == "DB")
{
s7AddressData.DataCode = (byte)S7Area.DB;
string[] strArray = strArr[index].Split('.');
s7AddressData.DbBlock = strArray[index][1] != 'B' ? Convert.ToUInt16(strArray[0].Substring(1)) : Convert.ToUInt16(strArray[0].Substring(2));
string address1 = strArr[index].Substring(strArr[index].IndexOf('.') + 1);
if (address1.StartsWith("DBX") || address1.StartsWith("DBB") || address1.StartsWith("DBW") || address1.StartsWith("DBD"))
{
address1 = address1.Substring(3);
}
s7AddressData.Address = GetAddressStart(address1).ToString();
s7AddressData.BitCode = GetBitCode(address1);
}
else if (strArr[index][0] == 'T')
{
s7AddressData.DataCode = (byte)S7Area.TM;
s7AddressData.Address = GetAddressStart(strArr[index].Substring(1), true).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1));
}
else if (strArr[index][0] == 'C')
{
s7AddressData.DataCode = (byte)S7Area.CT;
s7AddressData.Address = GetAddressStart(strArr[index].Substring(1), true).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1));
}
else if (strArr[index][0] == 'V')
{
s7AddressData.DataCode = (byte)S7Area.DB;
s7AddressData.DbBlock = 1;
if (strArr[index].StartsWith("VB") || strArr[index].StartsWith("VW") || strArr[index].StartsWith("VD") || strArr[index].StartsWith("VX"))
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2));
}
else
{
s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString();
s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1));
}
}
}
}
return s7AddressData;
}
@@ -242,44 +250,44 @@ public class SiemensAddress : DeviceAddressBase
{
if (DataCode == (byte)S7Area.TM)
{
return "T" + Address.ToString();
return $"T{Address.ToString()}{(IsWString ? ";W=true;" : ";W=false;")}";
}
if (DataCode == (byte)S7Area.CT)
{
return "C" + Address.ToString();
return $"C{Address.ToString()}{(IsWString ? ";W=true;" : ";W=false;")}";
}
if (DataCode == (byte)S7Area.AI)
{
return "AI" + GetStringAddress(AddressStart);
return $"AI{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
}
if (DataCode == (byte)S7Area.AQ)
{
return "AQ" + GetStringAddress(AddressStart);
return $"AQ{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
}
if (DataCode == (byte)S7Area.PE)
{
return "I" + GetStringAddress(AddressStart);
return $"I{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
}
if (DataCode == (byte)S7Area.PA)
{
return "Q" + GetStringAddress(AddressStart);
return $"Q{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
}
if (DataCode == (byte)S7Area.MK)
{
return "M" + GetStringAddress(AddressStart);
return $"M{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}";
}
return DataCode == (byte)S7Area.DB ? "DB" + DbBlock.ToString() + "." + GetStringAddress(AddressStart) : Address.ToString();
return DataCode == (byte)S7Area.DB ? $"DB{DbBlock.ToString()}.{GetStringAddress(AddressStart)}{(IsWString ? ";W=true;" : ";W=false;")}" : Address.ToString() + (IsWString ? ";W=true;" : ";W=false;");
}
private static string GetStringAddress(int addressStart)
{
return addressStart % 8 == 0 ? (addressStart / 8).ToString() : string.Format("{0}.{1}", addressStart / 8, addressStart % 8);
return addressStart % 8 == 0 ? (addressStart / 8).ToString() : $"{addressStart / 8}.{addressStart % 8}";
}
}

View File

@@ -10,8 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Adapter.Siemens;
/// <summary>

View File

@@ -10,8 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
namespace ThingsGateway.Foundation.Adapter.Siemens;
internal static class PackHelper
@@ -28,8 +26,7 @@ internal static class PackHelper
IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter);
item.ThingsGatewayBitConverter = transformParameter;
item.VariableAddress = address;//需要使用过滤后的地址
//item.VariableAddress = address;//需要使用过滤后的地址
item.Index = siemensS7Net.GetBitOffset(item.VariableAddress);
}
//按读取间隔分组
@@ -38,43 +35,55 @@ internal static class PackHelper
{
Dictionary<SiemensAddress, T2> map = item.ToDictionary(it =>
{
var lastLen = it.DataTypeEnum.GetByteLength();
if (lastLen <= 0)
{
switch (it.DataTypeEnum)
{
case DataTypeEnum.String:
if (it.ThingsGatewayBitConverter.Length == null)
{
throw new("数据类型为字符串时,必须指定字符串长度,才能进行打包");
}
else
{
if (siemensS7Net.CurrentPlc == SiemensEnum.S200Smart)
{
//字符串在S200Smart中第一个字节不属于实际内容
it.Index += 1;
//it.ThingsGatewayBitConverter.StringLength -= 1;
lastLen = it.ThingsGatewayBitConverter.Length.Value + 1;
}
else
{
//字符串在S7中前两个字节不属于实际内容
it.Index += 2;
//it.ThingsGatewayBitConverter.StringLength -= 2;
lastLen = it.ThingsGatewayBitConverter.Length.Value + 2;
}
}
break;
default:
lastLen = 1;
break;
}
}
try
{
var s7Address = SiemensAddress.ParseFrom(it.VariableAddress);
var lastLen = it.DataTypeEnum.GetByteLength();
if (lastLen <= 0)
{
switch (it.DataTypeEnum)
{
case DataTypeEnum.String:
if (it.ThingsGatewayBitConverter.Length == null)
{
throw new("数据类型为字符串时,必须指定字符串长度,才能进行打包");
}
else
{
if (siemensS7Net.CurrentPlc == SiemensEnum.S200Smart)
{
if (s7Address.IsWString)
{
//字符串在S200Smart中第一个字节不属于实际内容
it.Index += 1;
lastLen = it.ThingsGatewayBitConverter.Length.Value + 1;
}
else
{
lastLen = it.ThingsGatewayBitConverter.Length.Value;
}
}
else
{
if (s7Address.IsWString)
{
//字符串在S7中前两个字节不属于实际内容
it.Index += 2;
lastLen = it.ThingsGatewayBitConverter.Length.Value + 2;
}
else
{
lastLen = it.ThingsGatewayBitConverter.Length.Value;
}
}
}
break;
default:
lastLen = 1;
break;
}
}
if ((s7Address.DataCode == (byte)S7WordLength.Counter || s7Address.DataCode == (byte)S7WordLength.Timer) && lastLen == 1)
{
lastLen = 2;

View File

@@ -36,11 +36,42 @@ internal partial class SiemensHelper
// return OperResult.CreateSuccessResult<byte[]>(numArray);
//}
internal static OperResult<byte[]> AnalysisReadByte(byte[] sends, byte[] content)
internal static OperResult<byte[], FilterResult> AnalysisReadByte(byte[] sends, byte[] content)
{
int length = 0;
int itemLen = (sends.Length - 19) / 12;
//添加错误代码校验
if (content[17] + content[18] > 0)
{
return new($"PLC返回错误错误类型{content[17].ToString("X2")}错误代码:{content[18].ToString("X2")}")
{
Content2 = FilterResult.Success
};
}
if (content.Length < 21)
{
return new($"长度不足")
{
Content2 = FilterResult.Cache
};
}
if (content.Length < 25 + content[20])
{
return new($"长度不足")
{
Content2 = FilterResult.Cache
};
}
//添加返回代码校验
if (content[21] != 0xff)
{
return new($"PLC返回错误返回代码{content[21].ToString("X2")}")
{
Content2 = FilterResult.Success
};
}
for (int index = 0; index < itemLen; index++)
{
if (sends[22 + (index * 12)] >= (byte)S7WordLength.Word)
@@ -53,9 +84,9 @@ internal partial class SiemensHelper
}
}
if (content.Length < 21 || content[20] != itemLen)
if (content[20] != itemLen)
{
return new OperResult<byte[]>("数据块长度校验失败");
return new("数据块长度校验失败");
}
byte[] dataArray = new byte[length];
@@ -105,29 +136,39 @@ internal partial class SiemensHelper
}
else
{
return new OperResult<byte[]>((int)content[index2] + GetCpuError(content[index2]));
return new((int)content[index2] + GetCpuError(content[index2]))
{
Content2 = FilterResult.Success
};
}
}
}
return OperResult.CreateSuccessResult(dataArray);
return OperResult.CreateSuccessResult(dataArray, FilterResult.Success);
}
internal static OperResult<byte[]> AnalysisWrite(byte[] content)
internal static OperResult<byte[], FilterResult> AnalysisWrite(byte[] content)
{
if (content.Length < 22)
{
return new OperResult<byte[]>() { Message = "未知错误" };
return new()
{
Message = "长度不足",
Content2 = FilterResult.Success
};
}
byte err = content[21];
if (err != byte.MaxValue)
{
return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21]));
return new($"错误代码:{(int)content[21]}描述:{GetCpuError(content[21])}")
{
Content2 = FilterResult.Success
};
}
else
{
return OperResult.CreateSuccessResult(content);
return OperResult.CreateSuccessResult(content, FilterResult.Success);
}
}

View File

@@ -10,7 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
@@ -68,7 +67,6 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
break;
}
tcpClient.Connected += Connected;
}
/// <summary>
@@ -125,34 +123,7 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
#region
/// <summary>
/// 远程TSAP,需重新连接
/// </summary>
public int DestTSAP
{
get
{
return
_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart ?
(ISO_CR[17] * 256) + ISO_CR[18] :
(ISO_CR[20] * 256) + ISO_CR[21];
}
set
{
if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart)
{
ISO_CR[17] = BitConverter.GetBytes(value)[1];
ISO_CR[18] = BitConverter.GetBytes(value)[0];
}
else
{
ISO_CR[20] = BitConverter.GetBytes(value)[1];
ISO_CR[21] = BitConverter.GetBytes(value)[0];
}
}
}
/// <summary>
/// 本地TSAP需重新连接
/// 本地TSAP
/// </summary>
public int LocalTSAP
{
@@ -294,8 +265,8 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
/// <inheritdoc/>
public override void SetDataAdapter(object socketClient = null)
{
SiemensS7PLCDataHandleAdapter DataHandleAdapter = new();
TcpClient.SetDataHandlingAdapter(DataHandleAdapter);
SiemensS7PLCDataHandleAdapter dataHandleAdapter = new();
TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
}
@@ -477,17 +448,20 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
}
#endregion
private void Connected(ITcpClient client, ConnectedEventArgs e)
/// <inheritdoc/>
protected override async Task Connected(ITcpClient client, ConnectedEventArgs e)
{
try
{
var result1 = SendThenResponse(ISO_CR);
NormalDataHandlingAdapter dataHandleAdapter = new();
TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
var result1 = await SendThenResponseAsync(ISO_CR);
if (!result1.IsSuccess)
{
Logger?.Warning($"{client.IP} : {client.Port}ISO_TP握手失败-{result1.Message}");
return;
}
var result2 = SendThenResponse(S7_PN);
var result2 = await SendThenResponseAsync(S7_PN);
if (!result2.IsSuccess)
{
Logger?.Warning($"{client.IP} : {client.Port}PDU初始化失败-{result2.Message}");
@@ -500,7 +474,11 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
{
Logger.Exception(ex);
}
finally
{
SetDataAdapter();
}
await base.Connected(client, e);
}
}
}

View File

@@ -35,10 +35,10 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
/// <inheritdoc/>
protected override FilterResult UnpackResponse(SiemensMessage request, byte[] send, byte[] body, byte[] response)
{
var result = new OperResult<byte[]>();
var result = new OperResult<byte[], FilterResult>();
if (response[2] * 256 + response[3] == 7)
{
result = new OperResult<byte[]>() { Content = response };
result = new() { Content = response, Content2 = FilterResult.Success };
}
else
{
@@ -56,6 +56,6 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
request.ErrorCode = result.ErrorCode;
request.Message = result.Message;
request.Content = result.Content;
return FilterResult.Success;
return result.Content2;
}
}

View File

@@ -10,8 +10,6 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Siemens;

View File

@@ -0,0 +1,15 @@
0x00 Reserved 未定义,预留
0x01 Hardware error 硬件错误
0x03 Accessing the object not allowed 对象不允许访问
0x05 Invalid address 无效地址所需的地址超出此PLC的极限
0x06 Data type not supported 数据类型不支持
0x07 Data type inconsistent 日期类型不一致
0x0a Object does not exist 对象不存在
0xff Success 成功

View File

@@ -0,0 +1,825 @@
附录一:错误码具体含义
0x0000
没有错误
0x0110
块号无效
0x0111
请求长度无效
0x0112
参数无效
0x0113
块类型无效
0x0114
找不到块
0x0115
块已存在
0x0116
块被写保护
0x0117
块/操作系统更新太大
0x0118
块号无效
0x0119
输入的密码不正确
0x011A
PG资源错误
0x011B
PLC资源错误
0x011C
协议错误
0x011D
块太多(与模块相关的限制)
0x011E
不再与数据库建立连接或者S7DOS句柄无效
0x011F
结果缓冲区太小
0x0120
块结束列表
0x0140
可用内存不足
0x0141
由于缺少资源,无法处理作业
0x8001
当块处于当前状态时,无法执行请求的服务
0x8003
S7协议错误传输块时发生错误
0x8100
应用程序,一般错误:远程模块未知的服务
0x8104
未在模块上实现此服务或报告了帧错误
0x8204
对象的类型规范不一致
0x8205
复制的块已存在且未链接
0x8301
模块上的内存空间或工作内存不足,或者指定的存储介质不可访问
0x8302
可用资源太少或处理器资源不可用
0x8304
无法进一步并行上传。存在资源瓶颈
0x8305
功能不可用
0x8306
工作内存不足用于复制链接加载AWP
0x8307
保持性工作记忆不够用于复制链接加载AWP
0x8401
S7协议错误无效的服务序列例如加载或上载块
0x8402
由于寻址对象的状态,服务无法执行
0x8404
S7协议无法执行该功能
0x8405
远程块处于DISABLE状态CFB。该功能无法执行
0x8500
S7协议错误帧错误
0x8503
来自模块的警报:服务过早取消
0x8701
寻址通信伙伴上的对象时出错(例如,区域长度错误)
0x8702
模块不支持所请求的服务
0x8703
拒绝访问对象
0x8704
访问错误:对象已损坏
0xD001
协议错误:非法的作业号
0xD002
参数错误:非法的作业变体
0xD003
参数错误:模块不支持调试功能
0xD004
参数错误:作业状态非法
0xD005
参数错误:作业终止非法
0xD006
参数错误非法链路断开ID
0xD007
参数错误:缓冲区元素数量非法
0xD008
参数错误:扫描速率非法
0xD009
参数错误:执行次数非法
0xD00A
参数错误:非法触发事件
0xD00B
参数错误:非法触发条件
0xD011
调用环境路径中的参数错误:块不存在
0xD012
参数错误:块中的地址错误
0xD014
参数错误:正在删除/覆盖块
0xD015
参数错误:标签地址非法
0xD016
参数错误:由于用户程序错误,无法测试作业
0xD017
参数错误:非法触发号
0xD025
参数错误:路径无效
0xD026
参数错误:非法访问类型
0xD027
参数错误:不允许此数据块数
0xD031
内部协议错误
0xD032
参数错误:结果缓冲区长度错误
0xD033
协议错误:作业长度错误
0xD03F
编码错误参数部分出错例如保留字节不等于0
0xD041
数据错误非法状态列表ID
0xD042
数据错误:标签地址非法
0xD043
数据错误:找不到引用的作业,检查作业数据
0xD044
数据错误:标签值非法,检查作业数据
0xD045
数据错误HOLD中不允许退出ODIS控制
0xD046
数据错误:运行时测量期间非法测量阶段
0xD047
数据错误:“读取作业列表”中的非法层次结构
0xD048
数据错误“删除作业”中的非法删除ID
0xD049
“替换作业”中的替换ID无效
0xD04A
执行'程序状态'时出错
0xD05F
编码错误数据部分出错例如保留字节不等于0...
0xD061
资源错误:没有作业的内存空间
0xD062
资源错误:作业列表已满
0xD063
资源错误:触发事件占用
0xD064
资源错误:没有足够的内存空间用于一个结果缓冲区元素
0xD065
资源错误:没有足够的内存空间用于多个结果缓冲区元素
0xD066
资源错误:可用于运行时测量的计时器被另一个作业占用
0xD067
资源错误:“修改标记”作业过多(特别是多处理器操作)
0xD081
当前模式下不允许使用的功能
0xD082
模式错误无法退出HOLD模式
0xD0A1
当前保护级别不允许使用的功能
0xD0A2
目前无法运行,因为正在运行的函数会修改内存
0xD0A3
I / O上活动的“修改标记”作业太多特别是多处理器操作
0xD0A4
'强制'已经建立
0xD0A5
找不到引用的作业
0xD0A6
无法禁用/启用作业
0xD0A7
无法删除作业,例如因为当前正在读取作业
0xD0A8
无法替换作业,例如因为当前正在读取或删除作业
0xD0A9
无法读取作业,例如因为当前正在删除作业
0xD0AA
处理操作超出时间限制
0xD0AB
进程操作中的作业参数无效
0xD0AC
进程操作中的作业数据无效
0xD0AD
已设置操作模式
0xD0AE
作业是通过不同的连接设置的,只能通过此连接进行处理
0xD0C1
访问标签时至少检测到一个错误
0xD0C2
切换到STOP / HOLD模式
0xD0C3
访问标记时至少检测到一个错误。模式更改为STOP / HOLD
0xD0C4
运行时测量期间超时
0xD0C5
块堆栈的显示不一致,因为块被删除/重新加载
0xD0C6
作业已被删除,因为它所引用的作业已被删除
0xD0C7
由于退出了STOP模式因此作业被自动删除
0xD0C8
由于测试作业和正在运行的程序之间不一致,“块状态”中止
0xD0C9
通过复位OB90退出状态区域
0xD0CA
通过在退出前重置OB90并访问错误读取标签退出状态范围
0xD0CB
外设输出的输出禁用再次激活
0xD0CC
调试功能的数据量受时间限制
0xD201
块名称中的语法错误
0xD202
函数参数中的语法错误
0xD205
RAM中已存在链接块无法进行条件复制
0xD206
EPROM中已存在链接块无法进行条件复制
0xD208
超出模块的最大复制(未链接)块数
0xD209
(至少)模块上找不到给定块之一
0xD20A
超出了可以与一个作业链接的最大块数
0xD20B
超出了一个作业可以删除的最大块数
0xD20C
OB无法复制因为关联的优先级不存在
0xD20D
SDB无法解释例如未知数
0xD20E
没有(进一步)阻止可用
0xD20F
超出模块特定的最大块大小
0xD210
块号无效
0xD212
标头属性不正确(与运行时相关)
0xD213
SDB太多。请注意对正在使用的模块的限制
0xD216
无效的用户程序 - 重置模块
0xD217
不允许在模块属性中指定的保护级别
0xD218
属性不正确(主动/被动)
0xD219
块长度不正确(例如,第一部分或整个块的长度不正确)
0xD21A
本地数据长度不正确或写保护错误
0xD21B
模块无法压缩或压缩早期中断
0xD21D
传输的动态项目数据量是非法的
0xD21E
无法为模块例如FMCP分配参数。系统数据无法链接
0xD220
编程语言无效。请注意对正在使用的模块的限制
0xD221
连接或路由的系统数据无效
0xD222
全局数据定义的系统数据包含无效参数
0xD223
通信功能块的实例数据块错误或超出最大背景数据块数
0xD224
SCAN系统数据块包含无效参数
0xD225
DP系统数据块包含无效参数
0xD226
块中发生结构错误
0xD230
块中发生结构错误
0xD231
至少有一个已加载的OB无法复制因为关联的优先级不存在
0xD232
加载块的至少一个块编号是非法的
0xD234
块在指定的内存介质或作业中存在两次
0xD235
该块包含不正确的校验和
0xD236
该块不包含校验和
0xD237
您将要加载块两次即CPU上已存在具有相同时间戳的块
0xD238
指定的块中至少有一个不是DB
0xD239
至少有一个指定的DB在装载存储器中不可用作链接变量
0xD23A
至少有一个指定的DB与复制和链接的变体有很大不同
0xD240
违反了协调规则
0xD241
当前保护级别不允许该功能
0xD242
处理F块时的保护冲突
0xD250
更新和模块ID或版本不匹配
0xD251
操作系统组件序列不正确
0xD252
校验和错误
0xD253
没有可用的可执行加载程序; 只能使用存储卡进行更新
0xD254
操作系统中的存储错误
0xD280
在S7-300 CPU中编译块时出错
0xD2A1
块上的另一个块功能或触发器处于活动状态
0xD2A2
块上的触发器处于活动状态。首先完成调试功能
0xD2A3
块未激活(链接),块被占用或块当前被标记为删除
0xD2A4
该块已被另一个块函数处理
0xD2A6
无法同时保存和更改用户程序
0xD2A7
块具有“未链接”属性或未处理
0xD2A8
激活的调试功能阻止将参数分配给CPU
0xD2A9
正在为CPU分配新参数
0xD2AA
当前正在为模块分配新参数
0xD2AB
当前正在更改动态配置限制
0xD2AC
正在运行的激活或取消激活分配SFC 12暂时阻止R-KiR过程
0xD2B0
在RUNCiR中配置时发生错误
0xD2C0
已超出最大工艺对象数
0xD2C1
模块上已存在相同的技术数据块
0xD2C2
无法下载用户程序或下载硬件配置
0xD401
信息功能不可用
0xD402
信息功能不可用
0xD403
服务已登录/注销(诊断/ PMC
0xD404
达到的最大节点数。不再需要登录诊断/ PMC
0xD405
不支持服务或函数参数中的语法错误
0xD406
当前不可用的必需信息
0xD407
发生诊断错误
0xD408
更新已中止
0xD409
DP总线错误
0xD601
函数参数中的语法错误
0xD602
输入的密码不正确
0xD603
连接已合法化
0xD604
已启用连接
0xD605
由于密码不存在,因此无法进行合法化
0xD801
至少有一个标记地址无效
0xD802
指定的作业不存在
0xD803
非法的工作状态
0xD804
非法循环时间(非法时基或多个)
0xD805
不能再设置循环读取作业
0xD806
引用的作业处于无法执行请求的功能的状态
0xD807
功能因过载而中止,这意味着执行读取周期所需的时间比设置的扫描周期时间长
0xDC01
日期和/或时间无效
0xE201
CPU已经是主设备
0xE202
由于闪存模块中的用户程序不同,无法进行连接和更新
0xE203
由于固件不同,无法连接和更新
0xE204
由于内存配置不同,无法连接和更新
0xE205
由于同步错误导致连接/更新中止
0xE206
由于协调违规而拒绝连接/更新
0xEF01
S7协议错误ID2错误; 工作中只允许00H
0xEF02
S7协议错误ID2错误; 资源集不存在

View File

@@ -1,336 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>ThingsGateway.Foundation.Adapter.Siemens</name>
</assembly>
<members>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.S7Area">
<summary>
区域
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.PE">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.PA">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.MK">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.DB">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.CT">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.TM">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.AI">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.AQ">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress">
<summary>
西门子PLC地址数据信息
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.BitCode">
<summary>
bit位偏移
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.DataCode">
<summary>
数据块代码
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.DbBlock">
<summary>
DB块数据信息
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.GetAddressStart(System.String,System.Boolean)">
<summary>
获取起始地址
</summary>
<param name="address"></param>
<param name="isCounterOrTimer"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.GetBitCode(System.String)">
<summary>
获取bit
</summary>
<param name="address"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.ParseFrom(System.String)">
<summary>
解析地址
</summary>
<param name="address"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.ParseFrom(System.String,System.Int32)">
<summary>
解析地址
</summary>
<param name="address"></param>
<param name="length"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.Parse(System.String,System.Int32)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.ToString">
<inheritdoc />
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.DateTime">
<summary>
https://github.com/S7NetPlus/s7netplus/blob/develop/S7.Net/Types/DateTime.cs
Contains the methods to convert between <see cref="T:System.DateTime"/> and S7 representation of datetime values.
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMaximumDateTime">
<summary>
The maximum <see cref="T:System.DateTime"/> value supported by the specification.
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMinimumDateTime">
<summary>
The minimum <see cref="T:System.DateTime"/> value supported by the specification.
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.FromByteArray(System.Byte[])">
<summary>
Parses a <see cref="T:System.DateTime"/> value from bytes.
</summary>
<param name="bytes">Input bytes read from PLC.</param>
<returns>A <see cref="T:System.DateTime"/> object representing the value read from PLC.</returns>
<exception cref="T:System.ArgumentOutOfRangeException">Thrown when the length of
<paramref name="bytes"/> is not 8 or any value in <paramref name="bytes"/>
is outside the valid range of values.</exception>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToArray(System.Byte[])">
<summary>
Parses an array of <see cref="T:System.DateTime"/> values from bytes.
</summary>
<param name="bytes">Input bytes read from PLC.</param>
<returns>An array of <see cref="T:System.DateTime"/> objects representing the values read from PLC.</returns>
<exception cref="T:System.ArgumentOutOfRangeException">Thrown when the length of
<paramref name="bytes"/> is not a multiple of 8 or any value in
<paramref name="bytes"/> is outside the valid range of values.</exception>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToByteArray(System.DateTime)">
<summary>
Converts a <see cref="T:System.DateTime"/> value to a byte array.
</summary>
<param name="dateTime">The DateTime value to convert.</param>
<returns>A byte array containing the S7 date time representation of <paramref name="dateTime"/>.</returns>
<exception cref="T:System.ArgumentOutOfRangeException">Thrown when the value of
<paramref name="dateTime"/> is before <see cref="P:SpecMinimumDateTime"/>
or after <see cref="P:SpecMaximumDateTime"/>.</exception>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToByteArray(System.DateTime[])">
<summary>
Converts an array of <see cref="T:System.DateTime"/> values to a byte array.
</summary>
<param name="dateTimes">The DateTime values to convert.</param>
<returns>A byte array containing the S7 date time representations of <paramref name="dateTimes"/>.</returns>
<exception cref="T:System.ArgumentOutOfRangeException">Thrown when any value of
<paramref name="dateTimes"/> is before <see cref="P:SpecMinimumDateTime"/>
or after <see cref="P:SpecMaximumDateTime"/>.</exception>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensHelper.S7_MULRW_HEADER">
<summary>
S7连读写请求头(包含ISO头和COTP头)
</summary>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength">
<summary>
<inheritdoc/>
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Bit">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Byte">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Char">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Word">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Int">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.DWord">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.DInt">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Real">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Counter">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Timer">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage">
<inheritdoc/>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage.HeadBytesLength">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage.CheckHeadBytes(System.Byte[])">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum">
<summary>
<inheritdoc/>
</summary>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S200">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S200Smart">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S300">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S400">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S1200">
<inheritdoc/>
</member>
<member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S1500">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC">
<summary>
相关命令含义源自网络资料/Shrap7/s7netplus
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.#ctor(ThingsGateway.Foundation.TcpClient,ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum)">
<summary>
传入PLC类型程序内会改变相应PLC类型的S7协议LocalTSAP RemoteTSAP等
</summary>
<param name="tcpClient"></param>
<param name="siemensPLCEnum"></param>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.CurrentPlc">
<summary>
当前PLC类型
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.GetAddressDescription">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.GetBitOffset(System.String)">
<summary>
<inheritdoc/>
</summary>
<param name="address"></param>
<returns></returns>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.DestTSAP">
<summary>
远程TSAP需重新连接
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.LocalTSAP">
<summary>
本地TSAP需重新连接
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.PDULength">
<summary>
PDULength
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.Rack">
<summary>
机架号,需重新连接
</summary>
</member>
<member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.Slot">
<summary>
槽号,需重新连接
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadDateAsync(System.String,System.Threading.CancellationToken)">
<summary>
读取日期
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadDateTimeAsync(System.String,System.Threading.CancellationToken)">
<summary>
读取时间
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadStringAsync(System.String,System.Text.Encoding,System.Threading.CancellationToken)">
<summary>
读取变长字符串
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.SetDataAdapter">
<summary>
<inheritdoc/>
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteAsync(System.String,System.String,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteDateAsync(System.String,System.DateTime,System.Threading.CancellationToken)">
<summary>
写入日期
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteDateTimeAsync(System.String,System.DateTime,System.Threading.CancellationToken)">
<summary>
写入时间
</summary>
<returns></returns>
</member>
<member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter">
<summary>
SiemensS7PLCDataHandleAdapter
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter.PackCommand(System.Byte[])">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter.GetInstance">
<summary>
<inheritdoc/>
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage,System.Byte[],System.Byte[],System.Byte[])">
<inheritdoc/>
</member>
</members>
</doc>

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 设备地址数据的信息,对每个协议都建立其变量地址的表示类

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 打包读取变量

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 打包读取变量
/// </summary>

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 设备读写接口

View File

@@ -15,7 +15,7 @@ using System.Text;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 读写扩展方法

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// TCP读写设备
@@ -24,8 +24,8 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
public ReadWriteDevicesSerialSessionBase(SerialSession serialSession)
{
SerialSession = serialSession;
WaitingClientEx = SerialSession.GetWaitingClientEx(new() { BreakTrigger = true });
SerialSession.Received += Received;
WaitingClientEx = SerialSession.CreateWaitingClient(new() { });
SerialSession.Received -= Received;
SerialSession.Connecting -= Connecting;
SerialSession.Connected -= Connected;
SerialSession.Disconnecting -= Disconnecting;
@@ -34,26 +34,21 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
SerialSession.Connected += Connected;
SerialSession.Disconnecting += Disconnecting;
SerialSession.Disconnected += Disconnected;
SerialSession.Received += Received;
Logger = SerialSession.Logger;
}
/// <summary>
/// 接收解析
/// </summary>
protected virtual void Received(ByteBlock byteBlock, IRequestInfo requestInfo)
/// <param name="client"></param>
/// <param name="e"></param>
/// <returns></returns>
protected virtual Task Received(SerialSession client, ReceivedDataEventArgs e)
{
return EasyTask.CompletedTask;
}
}
private void Received(SerialSession client, ByteBlock byteBlock, IRequestInfo requestInfo)
{
try
{
Received(byteBlock, requestInfo);
}
catch (Exception ex)
{
Logger.Exception(this, ex);
}
}
/// <summary>
/// 串口管理对象
@@ -86,11 +81,12 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
/// <inheritdoc/>
public override void Dispose()
{
Disconnect();
SerialSession.Received -= Received;
SerialSession.Connecting -= Connecting;
SerialSession.Connected -= Connected;
SerialSession.Disconnecting -= Disconnecting;
SerialSession.Disconnected -= Disconnected;
Disconnect();
if (CascadeDisposal)
SerialSession.SafeDispose();
}
@@ -100,8 +96,8 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
{
try
{
waitingOptions ??= new WaitingOptions { BreakTrigger = true, ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
ResponsedData result = SerialSession.GetWaitingClientEx(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
waitingOptions ??= new WaitingOptions { };
ResponsedData result = SerialSession.CreateWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -115,8 +111,8 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
{
try
{
waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
ResponsedData result = await SerialSession.GetWaitingClientEx(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
waitingOptions ??= new WaitingOptions { };
ResponsedData result = await SerialSession.CreateWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -130,24 +126,34 @@ public abstract class ReadWriteDevicesSerialSessionBase : ReadWriteDevicesBase
{
return SerialSession.SerialProperty.ToString();
}
private void Connected(ISerialSession client, ConnectedEventArgs e)
/// <summary>
/// Connected
/// </summary>
/// <param name="client"></param>
/// <param name="e"></param>
/// <returns></returns>
protected virtual Task Connected(ISerialSession client, ConnectedEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "连接成功");
SetDataAdapter();
return EasyTask.CompletedTask;
}
private void Connecting(ISerialSession client, SerialConnectingEventArgs e)
private Task Connecting(ISerialSession client, SerialConnectingEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "正在连接");
SetDataAdapter();
return EasyTask.CompletedTask;
}
private void Disconnected(ISerialSessionBase client, DisconnectEventArgs e)
private Task Disconnected(ISerialSessionBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "断开连接-" + e.Message);
return EasyTask.CompletedTask;
}
private void Disconnecting(ISerialSessionBase client, DisconnectEventArgs e)
private Task Disconnecting(ISerialSessionBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.SerialProperty.ToString() + "正在主动断开连接-" + e.Message);
return EasyTask.CompletedTask;
}
}

View File

@@ -12,7 +12,7 @@
using System.ComponentModel;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// TCP读写设备
@@ -23,7 +23,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
public ReadWriteDevicesTcpClientBase(TcpClient tcpClient)
{
TcpClient = tcpClient;
WaitingClientEx = TcpClient.GetWaitingClientEx(new() { BreakTrigger = true });
WaitingClientEx = TcpClient.CreateWaitingClient(new() { });
TcpClient.Connecting -= Connecting;
TcpClient.Connected -= Connected;
TcpClient.Disconnecting -= Disconnecting;
@@ -59,7 +59,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
/// <inheritdoc/>
public override Task ConnectAsync(CancellationToken cancellationToken)
{
return TcpClient.ConnectAsync(ConnectTimeOut);
return TcpClient.ConnectAsync(ConnectTimeOut, cancellationToken);
}
/// <inheritdoc/>
@@ -72,11 +72,11 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
/// <inheritdoc/>
public override void Dispose()
{
Disconnect();
TcpClient.Connecting -= Connecting;
TcpClient.Connected -= Connected;
TcpClient.Disconnecting -= Disconnecting;
TcpClient.Disconnected -= Disconnected;
Disconnect();
if (CascadeDisposal)
TcpClient.SafeDispose();
}
@@ -86,8 +86,8 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
{
try
{
waitingOptions ??= new WaitingOptions { BreakTrigger = true, ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
ResponsedData result = TcpClient.GetWaitingClientEx(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
waitingOptions ??= new WaitingOptions { };
ResponsedData result = TcpClient.CreateWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -101,8 +101,8 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
{
try
{
waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
ResponsedData result = await TcpClient.GetWaitingClientEx(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
waitingOptions ??= new WaitingOptions { };
ResponsedData result = await TcpClient.CreateWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -116,24 +116,34 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesBase
{
return TcpClient.RemoteIPHost.ToString();
}
private void Connected(ITcpClient client, ConnectedEventArgs e)
/// <summary>
/// Connected
/// </summary>
/// <param name="client"></param>
/// <param name="e"></param>
/// <returns></returns>
protected virtual Task Connected(ITcpClient client, ConnectedEventArgs e)
{
Logger?.Debug(client.RemoteIPHost.ToString() + "连接成功");
SetDataAdapter();
return EasyTask.CompletedTask;
}
private void Connecting(ITcpClient client, ConnectingEventArgs e)
private Task Connecting(ITcpClient client, ConnectingEventArgs e)
{
Logger?.Debug(client.RemoteIPHost.ToString() + "正在连接");
SetDataAdapter();
return EasyTask.CompletedTask;
}
private void Disconnected(ITcpClientBase client, DisconnectEventArgs e)
private Task Disconnected(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message);
Logger?.Debug($"{client.IP}:{client.Port}断开连接-{e.Message}");
return EasyTask.CompletedTask;
}
private void Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
private Task Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message);
Logger?.Debug($"{client.IP}:{client.Port}正在主动断开连接-{e.Message}");
return EasyTask.CompletedTask;
}
}

View File

@@ -12,7 +12,7 @@
using System.ComponentModel;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 服务设备
@@ -23,9 +23,14 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
public ReadWriteDevicesTcpServerBase(TcpService tcpService)
{
TcpService = tcpService;
TcpService.Received -= Received;
TcpService.Connecting -= Connecting;
TcpService.Connected -= Connected;
TcpService.Disconnecting -= Disconnecting;
TcpService.Disconnected -= Disconnected;
TcpService.Received += Received;
TcpService.Connecting += Connecting;
TcpService.Connected += Connected;
TcpService.Received += Received;
TcpService.Disconnecting += Disconnecting;
TcpService.Disconnected += Disconnected;
Logger = TcpService.Logger;
@@ -50,7 +55,8 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
/// <inheritdoc/>
public override Task ConnectAsync(CancellationToken cancellationToken)
{
return Task.Run(() => TcpService.Start());
Connect(cancellationToken);
return EasyTask.CompletedTask;
}
/// <inheritdoc/>
@@ -63,65 +69,63 @@ public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase
/// <inheritdoc/>
public override void Dispose()
{
Disconnect();
TcpService.Received -= Received;
TcpService.Connecting -= Connecting;
TcpService.Connected -= Connected;
TcpService.Disconnecting -= Disconnecting;
TcpService.Disconnected -= Disconnected;
Disconnect();
if (CascadeDisposal)
TcpService.SafeDispose();
}
/// <summary>
/// 接收解析
/// </summary>
/// <param name="client"></param>
/// <param name="e"></param>
/// <returns></returns>
protected virtual Task Received(SocketClient client, ReceivedDataEventArgs e)
{
return EasyTask.CompletedTask;
}
/// <inheritdoc/>
public override string ToString()
{
return TcpService.ServerName;
}
/// <summary>
/// 接收解析
/// </summary>
protected virtual void Received(SocketClient client, IRequestInfo requestInfo)
{
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="client"></param>
/// <param name="e"></param>
protected virtual void Connected(SocketClient client, ConnectedEventArgs e)
protected virtual Task Connected(SocketClient client, ConnectedEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "连接成功");
Logger?.Debug($"{client.IP}:{client.Port}连接成功");
return EasyTask.CompletedTask;
}
/// <inheritdoc/>
protected virtual void Connecting(SocketClient client, ConnectingEventArgs e)
protected virtual Task Connecting(SocketClient client, ConnectingEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在连接");
Logger?.Debug($"{client.IP}:{client.Port}正在连接");
SetDataAdapter(client);
return EasyTask.CompletedTask;
}
/// <inheritdoc/>
protected virtual void Disconnected(ITcpClientBase client, DisconnectEventArgs e)
protected virtual Task Disconnected(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message);
Logger?.Debug($"{client.IP}:{client.Port}断开连接-{e.Message}");
return EasyTask.CompletedTask;
}
/// <inheritdoc/>
protected virtual void Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
protected virtual Task Disconnecting(ITcpClientBase client, DisconnectEventArgs e)
{
Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message);
Logger?.Debug($"{client.IP}:{client.Port}正在主动断开连接-{e.Message}");
return EasyTask.CompletedTask;
}
private void Received(SocketClient client, ByteBlock byteBlock, IRequestInfo requestInfo)
{
try
{
Received(client, requestInfo);
}
catch (Exception ex)
{
Logger.Exception(this, ex);
}
}
}

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// UDP读写设备
@@ -22,7 +22,7 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
{
UdpSession = udpSession;
SetDataAdapter();
WaitingClientEx = UdpSession.GetWaitingClientEx(new() { BreakTrigger = true });
WaitingClientEx = UdpSession.CreateWaitingClient(new() { });
}
/// <summary>
@@ -64,8 +64,8 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
{
try
{
waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
ResponsedData result = UdpSession.GetWaitingClientEx(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
waitingOptions ??= new WaitingOptions { };
ResponsedData result = UdpSession.CreateWaitingClient(waitingOptions).SendThenResponse(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)
@@ -79,8 +79,8 @@ public abstract class ReadWriteDevicesUdpSessionBase : ReadWriteDevicesBase
{
try
{
waitingOptions ??= new WaitingOptions { ThrowBreakException = true, AdapterFilter = AdapterFilter.NoneAll };
ResponsedData result = await UdpSession.GetWaitingClientEx(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
waitingOptions ??= new WaitingOptions { };
ResponsedData result = await UdpSession.CreateWaitingClient(waitingOptions).SendThenResponseAsync(data, TimeOut, cancellationToken);
return OperResult.CreateSuccessResult(result.Data);
}
catch (Exception ex)

View File

@@ -12,7 +12,7 @@
using System.Collections;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 线程安全的LinkedList

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// HSL摘录用于CRC16验证的类

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 自增

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// EasyLock使用轻量级SemaphoreSlim锁只允许一个并发量并记录并发信息
@@ -20,6 +20,12 @@ public sealed class EasyLock
private static long lockWaitCount;
private readonly SemaphoreSlim m_waiterLock = new SemaphoreSlim(1);
/// <inheritdoc/>
public EasyLock(bool initialState = true)
{
if (!initialState)
m_waiterLock.Wait();
}
/// <inheritdoc/>
~EasyLock()
{
m_waiterLock.SafeDispose();
@@ -45,39 +51,41 @@ public sealed class EasyLock
/// <summary>
/// 进入锁
/// </summary>
public void Wait()
public void Wait(CancellationToken cancellationToken = default)
{
Interlocked.Increment(ref lockWaitCount);
m_waiterLock.Wait();
m_waiterLock.Wait(cancellationToken);
Interlocked.Decrement(ref lockWaitCount);
}
/// <summary>
/// 进入锁
/// </summary>
public void Wait(TimeSpan timeSpan, CancellationToken cancellationToken)
public bool Wait(TimeSpan timeSpan, CancellationToken cancellationToken)
{
Interlocked.Increment(ref lockWaitCount);
m_waiterLock.Wait(timeSpan, cancellationToken);
var data = m_waiterLock.Wait(timeSpan, cancellationToken);
Interlocked.Decrement(ref lockWaitCount);
return data;
}
/// <summary>
/// 进入锁
/// </summary>
public async Task WaitAsync()
public async Task WaitAsync(CancellationToken cancellationToken = default)
{
Interlocked.Increment(ref lockWaitCount);
await m_waiterLock.WaitAsync();
await m_waiterLock.WaitAsync(cancellationToken);
Interlocked.Decrement(ref lockWaitCount);
}
/// <summary>
/// 进入锁
/// </summary>
public async Task WaitAsync(TimeSpan timeSpan, CancellationToken cancellationToken)
public async Task<bool> WaitAsync(TimeSpan timeSpan, CancellationToken cancellationToken)
{
Interlocked.Increment(ref lockWaitCount);
await m_waiterLock.WaitAsync(timeSpan, cancellationToken);
var data = await m_waiterLock.WaitAsync(timeSpan, cancellationToken);
Interlocked.Decrement(ref lockWaitCount);
return data;
}
}

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// TimerTick

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 常量

View File

@@ -10,15 +10,21 @@
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// TCP/Serial适配器基类
/// </summary>
public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDataHandlingAdapter<TRequest> where TRequest : class, IMessage
{
/// <summary>
/// 报文输出时采用字符串还是HexString
/// </summary>
public virtual bool IsHexData { get; set; } = true;
/// <inheritdoc cref="ReadWriteDevicesTcpDataHandleAdapter{TRequest}"/>
public ReadWriteDevicesTcpDataHandleAdapter()
{
@@ -46,7 +52,7 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
{
//获取全部内容
var allBytes = byteBlock.ToArray(0, byteBlock.Len);
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{allBytes.ToHexString(' ')}");
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{(IsHexData ? allBytes.ToHexString(' ') : Encoding.UTF8.GetString(allBytes))}");
//缓存/不缓存解析一样因为游标已经归0
{
request = Request;
@@ -131,7 +137,7 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
/// <summary>
/// 发送方法,会重新建立<see cref="Request"/>
/// </summary>
protected void GoSend(byte[] item)
protected virtual void GoSend(byte[] item)
{
byte[] bytes;
if (IsSendPackCommand)
@@ -141,7 +147,22 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
Request = GetInstance();
Request.SendBytes = bytes;
GoSend(bytes, 0, bytes.Length);
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{(IsHexData ? Request.SendBytes.ToHexString(' ') : Encoding.UTF8.GetString(Request.SendBytes))}");
}
/// <summary>
/// 发送方法,会重新建立<see cref="Request"/>
/// </summary>
protected virtual async Task GoSendAsync(byte[] item)
{
byte[] bytes;
if (IsSendPackCommand)
bytes = PackCommand(item);
else
bytes = item;
Request = GetInstance();
Request.SendBytes = bytes;
await GoSendAsync(bytes, 0, bytes.Length);
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{(IsHexData ? Request.SendBytes.ToHexString(' ') : Encoding.UTF8.GetString(Request.SendBytes))}");
}
/// <inheritdoc/>
@@ -150,6 +171,12 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
GoSend(buffer);
}
/// <inheritdoc/>
protected override Task PreviewSendAsync(byte[] buffer, int offset, int length)
{
return GoSendAsync(buffer);
}
/// <summary>
/// 报文拆包
/// </summary>
@@ -159,6 +186,13 @@ public abstract class ReadWriteDevicesTcpDataHandleAdapter<TRequest> : CustomDat
/// <inheritdoc/>
public override string ToString()
{
return Owner.ToString();
if (Owner is SocketClient client)
{
return client.GetIPPort();
}
else
{
return Owner.ToString();
}
}
}

View File

@@ -11,16 +11,24 @@
#endregion
using System.Net;
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// UDP适配器基类
/// </summary>
public abstract class ReadWriteDevicesUdpDataHandleAdapter<TRequest> : UdpDataHandlingAdapter where TRequest : class, IMessage
{
/// <summary>
/// 报文输出时采用字符串还是HexString
/// </summary>
public virtual bool IsHexData { get; set; } = true;
/// <inheritdoc cref="ReadWriteDevicesUdpDataHandleAdapter{TRequest}"/>
public ReadWriteDevicesUdpDataHandleAdapter()
{
@@ -68,13 +76,13 @@ public abstract class ReadWriteDevicesUdpDataHandleAdapter<TRequest> : UdpDataHa
Request = GetInstance();
Request.SendBytes = bytes;
GoSend(endPoint, bytes, 0, bytes.Length);
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{Request.SendBytes.ToHexString(' ')}");
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 发送:{(IsHexData ? Request.SendBytes.ToHexString(' ') : Encoding.UTF8.GetString(Request.SendBytes))}");
}
/// <inheritdoc/>
protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock)
{
var allBytes = byteBlock.ToArray(0, byteBlock.Len);
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{allBytes.ToHexString(' ')}");
Logger?.Trace($"{FoundationConst.LogMessageHeader}{ToString()}- 接收:{(IsHexData ? allBytes.ToHexString(' ') : Encoding.UTF8.GetString(allBytes))}");
if (Request?.SendBytes == null)
{
@@ -128,11 +136,6 @@ public abstract class ReadWriteDevicesUdpDataHandleAdapter<TRequest> : UdpDataHa
{
throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。
}
/// <inheritdoc/>
protected override void PreviewSend(IRequestInfo requestInfo)
{
throw new System.NotImplementedException();//因为设置了不支持,所以该方法可以不实现。
}
/// <inheritdoc/>
protected override void Reset()

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 数据类型

View File

@@ -10,13 +10,48 @@
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <inheritdoc/>
public static class ByteExtensions
{
/// <summary>
/// 获取异或校验
/// </summary>
/// <param name="data"></param>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static byte[] GetAsciiXOR(this byte[] data, int left, int right)
{
int tmp = data[left];
for (int i = left + 1; i < data.Length - right; i++)
{
tmp = (tmp ^ data[i]);
}
byte[] fcs = new byte[2];
fcs[0] = Encoding.ASCII.GetBytes(((byte)tmp).ToString("X2"))[0];
fcs[1] = Encoding.ASCII.GetBytes(((byte)tmp).ToString("X2"))[1];
return fcs;
}
/// <summary>
/// 数组内容分别相加某个数字
/// </summary>
/// <param name="bytes"></param>
/// <param name="value"></param>
/// <returns></returns>
public static byte[] BytesAdd(this byte[] bytes, int value)
{
for (int index = 0; index < bytes.Length; ++index)
bytes[index] = (byte)(bytes[index] + value);
return bytes;
}
/// <summary>
/// 获取byte数据类型的第offset位是否为True<br />
/// </summary>

View File

@@ -12,7 +12,7 @@
using System.Collections.Concurrent;
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>
/// 对象拓展

View File

@@ -10,7 +10,7 @@
//------------------------------------------------------------------------------
#endregion
namespace ThingsGateway.Foundation;
namespace ThingsGateway.Foundation.Core;
/// <summary>

View File

@@ -178,6 +178,10 @@ public static class GenericExtensions
/// <inheritdoc cref="DataTransUtil.SpliceArray" />
public static T[] SpliceArray<T>(this T[] value, params T[][] arrays)
{
if (value == null)
{
value = new T[0];
}
List<T[]> objArrayList = new(arrays.Length + 1)
{
value

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