Compare commits
	
		
			56 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ae818ca265 | ||
| 
						 | 
					0f2aed458e | ||
| 
						 | 
					d486c44ff6 | ||
| 
						 | 
					ca7b9980bf | ||
| 
						 | 
					3c71e6a8e3 | ||
| 
						 | 
					542442864c | ||
| 
						 | 
					5edb64fa85 | ||
| 
						 | 
					8dc1c898a3 | ||
| 
						 | 
					1ed35726b0 | ||
| 
						 | 
					27fae9ebaa | ||
| 
						 | 
					b103f25c94 | ||
| 
						 | 
					abff450274 | ||
| 
						 | 
					c260736a11 | ||
| 
						 | 
					166ac2307a | ||
| 
						 | 
					b21a4e1a4d | ||
| 
						 | 
					f7dc943fa3 | ||
| 
						 | 
					bfbd2693ec | ||
| 
						 | 
					819e71c993 | ||
| 
						 | 
					9fd0b489a2 | ||
| 
						 | 
					f5fe9f8dae | ||
| 
						 | 
					f9ffc18145 | ||
| 
						 | 
					08db5b983a | ||
| 
						 | 
					5b3b4c8c50 | ||
| 
						 | 
					73f914ffc4 | ||
| 
						 | 
					d6bdd73ed6 | ||
| 
						 | 
					7370ee7349 | ||
| 
						 | 
					4574596bac | ||
| 
						 | 
					4d16855e36 | ||
| 
						 | 
					13a0d4d282 | ||
| 
						 | 
					b9cd06b829 | ||
| 
						 | 
					5b460e8fa2 | ||
| 
						 | 
					41087edf17 | ||
| 
						 | 
					2afcc38e38 | ||
| 
						 | 
					e59ccce25f | ||
| 
						 | 
					d7425890e8 | ||
| 
						 | 
					a989a837fb | ||
| 
						 | 
					db1221da50 | ||
| 
						 | 
					cf794569ed | ||
| 
						 | 
					51e5bbab0d | ||
| 
						 | 
					2c197ed2b2 | ||
| 
						 | 
					d8fc6665b3 | ||
| 
						 | 
					c671a79822 | ||
| 
						 | 
					9d93ce4c41 | ||
| 
						 | 
					a6d99fe227 | ||
| 
						 | 
					923b8bca31 | ||
| 
						 | 
					e2c30d1c88 | ||
| 
						 | 
					b6d9f2a04e | ||
| 
						 | 
					57306ea664 | ||
| 
						 | 
					cd7f3fd02f | ||
| 
						 | 
					0482e077a8 | ||
| 
						 | 
					5f986a45ca | ||
| 
						 | 
					ca7b49c0d5 | ||
| 
						 | 
					52dd555e6c | ||
| 
						 | 
					579b1a59f9 | ||
| 
						 | 
					5299c5c4be | ||
| 
						 | 
					f7756bccef | 
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 **ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
 | 
					 **ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 **ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 [**ThingsGateway.Admin**](https://gitee.com/dotnetchina/ThingsGateway/blob/master/framework/ThingsGateway.Admin.sln)
 | 
					 **ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 **ThingsGateway - Admin**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 文档
 | 
					## 文档
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,149 +1,7 @@
 | 
				
			|||||||
[*.cs]
 | 
					[*.cs]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CA1822: 将成员标记为 static
 | 
					# CA1848: 使用 LoggerMessage 委托
 | 
				
			||||||
dotnet_diagnostic.CA1822.severity = none
 | 
					dotnet_diagnostic.CA1848.severity = none
 | 
				
			||||||
 | 
					 | 
				
			||||||
# CA1816: Dispose 方法应调用 SuppressFinalize
 | 
					 | 
				
			||||||
dotnet_diagnostic.CA1816.severity = none
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CA2254: 模板应为静态表达式
 | 
					# CA2254: 模板应为静态表达式
 | 
				
			||||||
dotnet_diagnostic.CA2254.severity = none
 | 
					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
 | 
					 | 
				
			||||||
csharp_using_directive_placement = outside_namespace:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_methods = false:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_constructors = false:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_operators = false:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_properties = true:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_indexers = true:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_accessors = true:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_lambdas = true:silent
 | 
					 | 
				
			||||||
csharp_style_expression_bodied_local_functions = false:silent
 | 
					 | 
				
			||||||
csharp_style_conditional_delegate_call = true:suggestion
 | 
					 | 
				
			||||||
csharp_style_var_for_built_in_types = false:silent
 | 
					 | 
				
			||||||
csharp_style_var_when_type_is_apparent = false:silent
 | 
					 | 
				
			||||||
csharp_style_var_elsewhere = false:silent
 | 
					 | 
				
			||||||
csharp_prefer_simple_using_statement = true:suggestion
 | 
					 | 
				
			||||||
csharp_prefer_braces = true:silent
 | 
					 | 
				
			||||||
csharp_style_namespace_declarations = block_scoped:silent
 | 
					 | 
				
			||||||
csharp_style_prefer_method_group_conversion = true:silent
 | 
					 | 
				
			||||||
csharp_style_prefer_top_level_statements = true:silent
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# CA2208: 正确实例化参数异常
 | 
					 | 
				
			||||||
dotnet_diagnostic.CA2208.severity = none
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# IDE0057: 使用范围运算符
 | 
					 | 
				
			||||||
dotnet_diagnostic.IDE0057.severity = none
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# IDE0056: 使用索引运算符
 | 
					 | 
				
			||||||
dotnet_diagnostic.IDE0056.severity = none
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# CA1830: 最好使用 StringBuilder 的强类型 Append 和 Insert 方法重载
 | 
					 | 
				
			||||||
dotnet_diagnostic.CA1830.severity = none
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# CA1847: 将字符型文本用于单个字符查找
 | 
					 | 
				
			||||||
dotnet_diagnostic.CA1847.severity = none
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[*.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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[*.{cs,vb}]
 | 
					 | 
				
			||||||
dotnet_style_qualification_for_field = false:silent
 | 
					 | 
				
			||||||
dotnet_style_qualification_for_property = false:silent
 | 
					 | 
				
			||||||
dotnet_style_qualification_for_method = false:silent
 | 
					 | 
				
			||||||
dotnet_style_qualification_for_event = false:silent
 | 
					 | 
				
			||||||
end_of_line = crlf
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# IDE0060: 删除未使用的参数
 | 
					 | 
				
			||||||
dotnet_diagnostic.IDE0060.severity = none
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										63
									
								
								framework/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								framework/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# Set default behavior to automatically normalize line endings.
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					* text=auto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# Set default behavior for command prompt diff.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This is need for earlier builds of msysgit that does not have it on by
 | 
				
			||||||
 | 
					# default for csharp files.
 | 
				
			||||||
 | 
					# Note: This is only used by command line
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					#*.cs     diff=csharp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# Set the merge driver for project and solution files
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Merging from the command prompt will add diff markers to the files if there
 | 
				
			||||||
 | 
					# are conflicts (Merging from VS is not affected by the settings below, in VS
 | 
				
			||||||
 | 
					# the diff markers are never inserted). Diff markers may cause the following 
 | 
				
			||||||
 | 
					# file extensions to fail to load in VS. An alternative would be to treat
 | 
				
			||||||
 | 
					# these files as binary and thus will always conflict and require user
 | 
				
			||||||
 | 
					# intervention with every merge. To do so, just uncomment the entries below
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					#*.sln       merge=binary
 | 
				
			||||||
 | 
					#*.csproj    merge=binary
 | 
				
			||||||
 | 
					#*.vbproj    merge=binary
 | 
				
			||||||
 | 
					#*.vcxproj   merge=binary
 | 
				
			||||||
 | 
					#*.vcproj    merge=binary
 | 
				
			||||||
 | 
					#*.dbproj    merge=binary
 | 
				
			||||||
 | 
					#*.fsproj    merge=binary
 | 
				
			||||||
 | 
					#*.lsproj    merge=binary
 | 
				
			||||||
 | 
					#*.wixproj   merge=binary
 | 
				
			||||||
 | 
					#*.modelproj merge=binary
 | 
				
			||||||
 | 
					#*.sqlproj   merge=binary
 | 
				
			||||||
 | 
					#*.wwaproj   merge=binary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# behavior for image files
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# image files are treated as binary by default.
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					#*.jpg   binary
 | 
				
			||||||
 | 
					#*.png   binary
 | 
				
			||||||
 | 
					#*.gif   binary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# diff behavior for common document formats
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# Convert binary document formats to text before diffing them. This feature
 | 
				
			||||||
 | 
					# is only available from the command line. Turn it on by uncommenting the 
 | 
				
			||||||
 | 
					# entries below.
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					#*.doc   diff=astextplain
 | 
				
			||||||
 | 
					#*.DOC   diff=astextplain
 | 
				
			||||||
 | 
					#*.docx  diff=astextplain
 | 
				
			||||||
 | 
					#*.DOCX  diff=astextplain
 | 
				
			||||||
 | 
					#*.dot   diff=astextplain
 | 
				
			||||||
 | 
					#*.DOT   diff=astextplain
 | 
				
			||||||
 | 
					#*.pdf   diff=astextplain
 | 
				
			||||||
 | 
					#*.PDF   diff=astextplain
 | 
				
			||||||
 | 
					#*.rtf   diff=astextplain
 | 
				
			||||||
 | 
					#*.RTF   diff=astextplain
 | 
				
			||||||
							
								
								
									
										364
									
								
								framework/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										364
									
								
								framework/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,364 @@
 | 
				
			|||||||
 | 
					## Ignore Visual Studio temporary files, build results, and
 | 
				
			||||||
 | 
					## files generated by popular Visual Studio add-ons.
 | 
				
			||||||
 | 
					##
 | 
				
			||||||
 | 
					## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User-specific files
 | 
				
			||||||
 | 
					*.rsuser
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.user
 | 
				
			||||||
 | 
					*.userosscache
 | 
				
			||||||
 | 
					*.sln.docstates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User-specific files (MonoDevelop/Xamarin Studio)
 | 
				
			||||||
 | 
					*.userprefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mono auto generated files
 | 
				
			||||||
 | 
					mono_crash.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build results
 | 
				
			||||||
 | 
					[Dd]ebug/
 | 
				
			||||||
 | 
					[Dd]ebugPublic/
 | 
				
			||||||
 | 
					[Rr]elease/
 | 
				
			||||||
 | 
					[Rr]eleases/
 | 
				
			||||||
 | 
					x64/
 | 
				
			||||||
 | 
					x86/
 | 
				
			||||||
 | 
					[Ww][Ii][Nn]32/
 | 
				
			||||||
 | 
					[Aa][Rr][Mm]/
 | 
				
			||||||
 | 
					[Aa][Rr][Mm]64/
 | 
				
			||||||
 | 
					bld/
 | 
				
			||||||
 | 
					[Bb]in/
 | 
				
			||||||
 | 
					[Oo]bj/
 | 
				
			||||||
 | 
					[Oo]ut/
 | 
				
			||||||
 | 
					[Ll]og/
 | 
				
			||||||
 | 
					[Ll]ogs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 2015/2017 cache/options directory
 | 
				
			||||||
 | 
					.vs/
 | 
				
			||||||
 | 
					# Uncomment if you have tasks that create the project's static files in wwwroot
 | 
				
			||||||
 | 
					#wwwroot/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 2017 auto generated files
 | 
				
			||||||
 | 
					Generated\ Files/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MSTest test Results
 | 
				
			||||||
 | 
					[Tt]est[Rr]esult*/
 | 
				
			||||||
 | 
					[Bb]uild[Ll]og.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NUnit
 | 
				
			||||||
 | 
					*.VisualState.xml
 | 
				
			||||||
 | 
					TestResult.xml
 | 
				
			||||||
 | 
					nunit-*.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build Results of an ATL Project
 | 
				
			||||||
 | 
					[Dd]ebugPS/
 | 
				
			||||||
 | 
					[Rr]eleasePS/
 | 
				
			||||||
 | 
					dlldata.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Benchmark Results
 | 
				
			||||||
 | 
					BenchmarkDotNet.Artifacts/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# .NET Core
 | 
				
			||||||
 | 
					project.lock.json
 | 
				
			||||||
 | 
					project.fragment.lock.json
 | 
				
			||||||
 | 
					artifacts/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ASP.NET Scaffolding
 | 
				
			||||||
 | 
					ScaffoldingReadMe.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# StyleCop
 | 
				
			||||||
 | 
					StyleCopReport.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Files built by Visual Studio
 | 
				
			||||||
 | 
					*_i.c
 | 
				
			||||||
 | 
					*_p.c
 | 
				
			||||||
 | 
					*_h.h
 | 
				
			||||||
 | 
					*.ilk
 | 
				
			||||||
 | 
					*.meta
 | 
				
			||||||
 | 
					*.obj
 | 
				
			||||||
 | 
					*.iobj
 | 
				
			||||||
 | 
					*.pch
 | 
				
			||||||
 | 
					*.pdb
 | 
				
			||||||
 | 
					*.ipdb
 | 
				
			||||||
 | 
					*.pgc
 | 
				
			||||||
 | 
					*.pgd
 | 
				
			||||||
 | 
					*.rsp
 | 
				
			||||||
 | 
					*.sbr
 | 
				
			||||||
 | 
					*.tlb
 | 
				
			||||||
 | 
					*.tli
 | 
				
			||||||
 | 
					*.tlh
 | 
				
			||||||
 | 
					*.tmp
 | 
				
			||||||
 | 
					*.tmp_proj
 | 
				
			||||||
 | 
					*_wpftmp.csproj
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					*.vspscc
 | 
				
			||||||
 | 
					*.vssscc
 | 
				
			||||||
 | 
					.builds
 | 
				
			||||||
 | 
					*.pidb
 | 
				
			||||||
 | 
					*.svclog
 | 
				
			||||||
 | 
					*.scc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Chutzpah Test files
 | 
				
			||||||
 | 
					_Chutzpah*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual C++ cache files
 | 
				
			||||||
 | 
					ipch/
 | 
				
			||||||
 | 
					*.aps
 | 
				
			||||||
 | 
					*.ncb
 | 
				
			||||||
 | 
					*.opendb
 | 
				
			||||||
 | 
					*.opensdf
 | 
				
			||||||
 | 
					*.sdf
 | 
				
			||||||
 | 
					*.cachefile
 | 
				
			||||||
 | 
					*.VC.db
 | 
				
			||||||
 | 
					*.VC.VC.opendb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio profiler
 | 
				
			||||||
 | 
					*.psess
 | 
				
			||||||
 | 
					*.vsp
 | 
				
			||||||
 | 
					*.vspx
 | 
				
			||||||
 | 
					*.sap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio Trace Files
 | 
				
			||||||
 | 
					*.e2e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TFS 2012 Local Workspace
 | 
				
			||||||
 | 
					$tf/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Guidance Automation Toolkit
 | 
				
			||||||
 | 
					*.gpState
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ReSharper is a .NET coding add-in
 | 
				
			||||||
 | 
					_ReSharper*/
 | 
				
			||||||
 | 
					*.[Rr]e[Ss]harper
 | 
				
			||||||
 | 
					*.DotSettings.user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TeamCity is a build add-in
 | 
				
			||||||
 | 
					_TeamCity*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DotCover is a Code Coverage Tool
 | 
				
			||||||
 | 
					*.dotCover
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# AxoCover is a Code Coverage Tool
 | 
				
			||||||
 | 
					.axoCover/*
 | 
				
			||||||
 | 
					!.axoCover/settings.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Coverlet is a free, cross platform Code Coverage Tool
 | 
				
			||||||
 | 
					coverage*.json
 | 
				
			||||||
 | 
					coverage*.xml
 | 
				
			||||||
 | 
					coverage*.info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio code coverage results
 | 
				
			||||||
 | 
					*.coverage
 | 
				
			||||||
 | 
					*.coveragexml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NCrunch
 | 
				
			||||||
 | 
					_NCrunch_*
 | 
				
			||||||
 | 
					.*crunch*.local.xml
 | 
				
			||||||
 | 
					nCrunchTemp_*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MightyMoose
 | 
				
			||||||
 | 
					*.mm.*
 | 
				
			||||||
 | 
					AutoTest.Net/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Web workbench (sass)
 | 
				
			||||||
 | 
					.sass-cache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Installshield output folder
 | 
				
			||||||
 | 
					[Ee]xpress/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DocProject is a documentation generator add-in
 | 
				
			||||||
 | 
					DocProject/buildhelp/
 | 
				
			||||||
 | 
					DocProject/Help/*.HxT
 | 
				
			||||||
 | 
					DocProject/Help/*.HxC
 | 
				
			||||||
 | 
					DocProject/Help/*.hhc
 | 
				
			||||||
 | 
					DocProject/Help/*.hhk
 | 
				
			||||||
 | 
					DocProject/Help/*.hhp
 | 
				
			||||||
 | 
					DocProject/Help/Html2
 | 
				
			||||||
 | 
					DocProject/Help/html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Click-Once directory
 | 
				
			||||||
 | 
					publish/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Publish Web Output
 | 
				
			||||||
 | 
					*.[Pp]ublish.xml
 | 
				
			||||||
 | 
					*.azurePubxml
 | 
				
			||||||
 | 
					# Note: Comment the next line if you want to checkin your web deploy settings,
 | 
				
			||||||
 | 
					# but database connection strings (with potential passwords) will be unencrypted
 | 
				
			||||||
 | 
					*.pubxml
 | 
				
			||||||
 | 
					*.publishproj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Microsoft Azure Web App publish settings. Comment the next line if you want to
 | 
				
			||||||
 | 
					# checkin your Azure Web App publish settings, but sensitive information contained
 | 
				
			||||||
 | 
					# in these scripts will be unencrypted
 | 
				
			||||||
 | 
					PublishScripts/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NuGet Packages
 | 
				
			||||||
 | 
					*.nupkg
 | 
				
			||||||
 | 
					# NuGet Symbol Packages
 | 
				
			||||||
 | 
					*.snupkg
 | 
				
			||||||
 | 
					# The packages folder can be ignored because of Package Restore
 | 
				
			||||||
 | 
					**/[Pp]ackages/*
 | 
				
			||||||
 | 
					# except build/, which is used as an MSBuild target.
 | 
				
			||||||
 | 
					!**/[Pp]ackages/build/
 | 
				
			||||||
 | 
					# Uncomment if necessary however generally it will be regenerated when needed
 | 
				
			||||||
 | 
					#!**/[Pp]ackages/repositories.config
 | 
				
			||||||
 | 
					# NuGet v3's project.json files produces more ignorable files
 | 
				
			||||||
 | 
					*.nuget.props
 | 
				
			||||||
 | 
					*.nuget.targets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Microsoft Azure Build Output
 | 
				
			||||||
 | 
					csx/
 | 
				
			||||||
 | 
					*.build.csdef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Microsoft Azure Emulator
 | 
				
			||||||
 | 
					ecf/
 | 
				
			||||||
 | 
					rcf/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows Store app package directories and files
 | 
				
			||||||
 | 
					AppPackages/
 | 
				
			||||||
 | 
					BundleArtifacts/
 | 
				
			||||||
 | 
					Package.StoreAssociation.xml
 | 
				
			||||||
 | 
					_pkginfo.txt
 | 
				
			||||||
 | 
					*.appx
 | 
				
			||||||
 | 
					*.appxbundle
 | 
				
			||||||
 | 
					*.appxupload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio cache files
 | 
				
			||||||
 | 
					# files ending in .cache can be ignored
 | 
				
			||||||
 | 
					*.[Cc]ache
 | 
				
			||||||
 | 
					# but keep track of directories ending in .cache
 | 
				
			||||||
 | 
					!?*.[Cc]ache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Others
 | 
				
			||||||
 | 
					ClientBin/
 | 
				
			||||||
 | 
					~$*
 | 
				
			||||||
 | 
					*~
 | 
				
			||||||
 | 
					*.dbmdl
 | 
				
			||||||
 | 
					*.dbproj.schemaview
 | 
				
			||||||
 | 
					*.jfm
 | 
				
			||||||
 | 
					*.pfx
 | 
				
			||||||
 | 
					*.publishsettings
 | 
				
			||||||
 | 
					orleans.codegen.cs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Including strong name files can present a security risk
 | 
				
			||||||
 | 
					# (https://github.com/github/gitignore/pull/2483#issue-259490424)
 | 
				
			||||||
 | 
					#*.snk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Since there are multiple workflows, uncomment next line to ignore bower_components
 | 
				
			||||||
 | 
					# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
 | 
				
			||||||
 | 
					#bower_components/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# RIA/Silverlight projects
 | 
				
			||||||
 | 
					Generated_Code/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Backup & report files from converting an old project file
 | 
				
			||||||
 | 
					# to a newer Visual Studio version. Backup files are not needed,
 | 
				
			||||||
 | 
					# because we have git ;-)
 | 
				
			||||||
 | 
					_UpgradeReport_Files/
 | 
				
			||||||
 | 
					Backup*/
 | 
				
			||||||
 | 
					UpgradeLog*.XML
 | 
				
			||||||
 | 
					UpgradeLog*.htm
 | 
				
			||||||
 | 
					ServiceFabricBackup/
 | 
				
			||||||
 | 
					*.rptproj.bak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SQL Server files
 | 
				
			||||||
 | 
					*.mdf
 | 
				
			||||||
 | 
					*.ldf
 | 
				
			||||||
 | 
					*.ndf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Business Intelligence projects
 | 
				
			||||||
 | 
					*.rdl.data
 | 
				
			||||||
 | 
					*.bim.layout
 | 
				
			||||||
 | 
					*.bim_*.settings
 | 
				
			||||||
 | 
					*.rptproj.rsuser
 | 
				
			||||||
 | 
					*- [Bb]ackup.rdl
 | 
				
			||||||
 | 
					*- [Bb]ackup ([0-9]).rdl
 | 
				
			||||||
 | 
					*- [Bb]ackup ([0-9][0-9]).rdl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Microsoft Fakes
 | 
				
			||||||
 | 
					FakesAssemblies/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# GhostDoc plugin setting file
 | 
				
			||||||
 | 
					*.GhostDoc.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Node.js Tools for Visual Studio
 | 
				
			||||||
 | 
					.ntvs_analysis.dat
 | 
				
			||||||
 | 
					node_modules/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 6 build log
 | 
				
			||||||
 | 
					*.plg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 6 workspace options file
 | 
				
			||||||
 | 
					*.opt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
 | 
				
			||||||
 | 
					*.vbw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio LightSwitch build output
 | 
				
			||||||
 | 
					**/*.HTMLClient/GeneratedArtifacts
 | 
				
			||||||
 | 
					**/*.DesktopClient/GeneratedArtifacts
 | 
				
			||||||
 | 
					**/*.DesktopClient/ModelManifest.xml
 | 
				
			||||||
 | 
					**/*.Server/GeneratedArtifacts
 | 
				
			||||||
 | 
					**/*.Server/ModelManifest.xml
 | 
				
			||||||
 | 
					_Pvt_Extensions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Paket dependency manager
 | 
				
			||||||
 | 
					.paket/paket.exe
 | 
				
			||||||
 | 
					paket-files/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FAKE - F# Make
 | 
				
			||||||
 | 
					.fake/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CodeRush personal settings
 | 
				
			||||||
 | 
					.cr/personal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python Tools for Visual Studio (PTVS)
 | 
				
			||||||
 | 
					__pycache__/
 | 
				
			||||||
 | 
					*.pyc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cake - Uncomment if you are using it
 | 
				
			||||||
 | 
					# tools/**
 | 
				
			||||||
 | 
					# !tools/packages.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tabs Studio
 | 
				
			||||||
 | 
					*.tss
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Telerik's JustMock configuration file
 | 
				
			||||||
 | 
					*.jmconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# BizTalk build output
 | 
				
			||||||
 | 
					*.btp.cs
 | 
				
			||||||
 | 
					*.btm.cs
 | 
				
			||||||
 | 
					*.odx.cs
 | 
				
			||||||
 | 
					*.xsd.cs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# OpenCover UI analysis results
 | 
				
			||||||
 | 
					OpenCover/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Azure Stream Analytics local run output
 | 
				
			||||||
 | 
					ASALocalRun/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MSBuild Binary and Structured Log
 | 
				
			||||||
 | 
					*.binlog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NVidia Nsight GPU debugger configuration file
 | 
				
			||||||
 | 
					*.nvuser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MFractors (Xamarin productivity tool) working folder
 | 
				
			||||||
 | 
					.mfractor/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Local History for Visual Studio
 | 
				
			||||||
 | 
					.localhistory/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# BeatPulse healthcheck temp database
 | 
				
			||||||
 | 
					healthchecksdb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Backup folder for Package Reference Convert tool in Visual Studio 2017
 | 
				
			||||||
 | 
					MigrationBackup/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Ionide (cross platform F# VS Code tools) working folder
 | 
				
			||||||
 | 
					.ionide/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Fody - auto-generated XML schema
 | 
				
			||||||
 | 
					FodyWeavers.xsd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								framework/Demo/Directory.Build.props
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								framework/Demo/Directory.Build.props
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<Project>
 | 
				
			||||||
 | 
						<PropertyGroup>
 | 
				
			||||||
 | 
							<Version>3.0.0.0</Version>
 | 
				
			||||||
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
 | 
							<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
 | 
							<Authors>Diego</Authors>
 | 
				
			||||||
 | 
							<Product>ThingsGateway</Product>
 | 
				
			||||||
 | 
							<Copyright>© 2023-present Diego</Copyright>
 | 
				
			||||||
 | 
							<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl>
 | 
				
			||||||
 | 
							<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
 | 
				
			||||||
 | 
							<GenerateDocumentationFile>False</GenerateDocumentationFile>
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -12,4 +12,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
global using System;
 | 
					global using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
global using TouchSocket.Core;
 | 
					global using ThingsGateway.Components;
 | 
				
			||||||
@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Photino.Blazor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class Program
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [STAThread]
 | 
				
			||||||
 | 
					    private static void Main(string[] args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        System.IO.Directory.SetCurrentDirectory(AppContext.BaseDirectory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        appBuilder.RootComponents.Add<App>("#app");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        appBuilder.Services.ThingsGatewayComponentsConfigureServices();
 | 
				
			||||||
 | 
					        var app = appBuilder.Build();
 | 
				
			||||||
 | 
					        app.MainWindow.SetTitle("ThingsGateway.Foundation.Demo");
 | 
				
			||||||
 | 
					        app.MainWindow.SetIconFile("wwwroot/favicon.ico");
 | 
				
			||||||
 | 
					        AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        app.Run();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk.Razor">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<PropertyGroup>
 | 
				
			||||||
 | 
							<OutputType>WinExe</OutputType>
 | 
				
			||||||
 | 
							<ApplicationIcon>favicon.ico</ApplicationIcon>
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
						  <None Remove="favicon.ico" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
						  <Content Include="favicon.ico">
 | 
				
			||||||
 | 
						    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
 | 
				
			||||||
 | 
						    <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
 | 
				
			||||||
 | 
						    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
 | 
				
			||||||
 | 
						  </Content>
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<PackageReference Include="Photino.Blazor" Version="2.6.0" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
						  <ProjectReference Include="..\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								framework/Demo/ThingsGateway.Foundation.Demo.Photino/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								framework/Demo/ThingsGateway.Foundation.Demo.Photino/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										26
									
								
								framework/Demo/ThingsGateway.Foundation.Demo.Rcl/App.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								framework/Demo/ThingsGateway.Foundation.Demo.Rcl/App.razor
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Router AppAssembly="@typeof(App).Assembly">
 | 
				
			||||||
 | 
					    <Found Context="routeData">
 | 
				
			||||||
 | 
					        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
 | 
				
			||||||
 | 
					        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
 | 
				
			||||||
 | 
					    </Found>
 | 
				
			||||||
 | 
					    <NotFound>
 | 
				
			||||||
 | 
					        <LayoutView Layout="@typeof(MainLayout)">
 | 
				
			||||||
 | 
					            <p role="alert">Sorry, there's nothing at this address.</p>
 | 
				
			||||||
 | 
					        </LayoutView>
 | 
				
			||||||
 | 
					    </NotFound>
 | 
				
			||||||
 | 
					</Router>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					using LogLevel = Microsoft.Extensions.Logging.LogLevel;
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// 调试UI
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public abstract class DriverDebugUIBase : ComponentBase, IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 日志缓存
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public ConcurrentLinkedList<(LogLevel level, string message)> Messages = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    ~DriverDebugUIBase()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 变量地址
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public virtual string Address { get; set; } = "40001";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 长度
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public virtual int Length { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 默认读写设备
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public virtual IReadWrite Plc { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 写入值
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public virtual string WriteValue { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 数据类型
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    protected virtual DataTypeEnum DataTypeEnum { get; set; } = DataTypeEnum.Int16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Inject]
 | 
				
			||||||
 | 
					    public InitTimezone InitTimezone { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public virtual void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _periodicTimer?.Dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public void LogOut(ThingsGateway.Foundation.LogLevel logLevel, object source, string message, Exception exception)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Messages.Add(((LogLevel)logLevel,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {message} {exception}"));
 | 
				
			||||||
 | 
					        if (Messages.Count > 2500)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Messages.Clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public virtual async Task ReadAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var data = await Plc.ReadAsync(Address, Length, DataTypeEnum);
 | 
				
			||||||
 | 
					            if (data.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Messages.Add((LogLevel.Information,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 对应类型值:{Environment.NewLine}{data.Content.ToJsonString(true)} "));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Messages.Add((LogLevel.Warning,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}"));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Messages.Add((LogLevel.Error,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex.Message}"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public virtual async Task WriteAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var data = await Plc.WriteAsync(Address, WriteValue, Length, DataTypeEnum);
 | 
				
			||||||
 | 
					            if (data.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Messages.Add((LogLevel.Information,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}"));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Messages.Add((LogLevel.Warning,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}"));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Messages.Add((LogLevel.Error,
 | 
				
			||||||
 | 
					            $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex.Message}"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _ = RunTimerAsync();
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private async Task RunTimerAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        while (await _periodicTimer.WaitForNextTickAsync())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await InvokeAsync(StateHasChanged);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,205 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@using BlazorComponent;
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
 | 
					@using Microsoft.JSInterop;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					@using Masa.Blazor;
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					@inherits DriverDebugUIBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<MCard Elevation="1" Rounded="false" Class=" pa-2" Style="width:100%">
 | 
				
			||||||
 | 
					    <MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <MCol Md="5">
 | 
				
			||||||
 | 
					            <MTabs @bind-Value="tab" Class="ma-2">
 | 
				
			||||||
 | 
					                <MTab Value=1>   读写测试    </MTab>
 | 
				
			||||||
 | 
					                <MTab Value=2>    特殊功能    </MTab>
 | 
				
			||||||
 | 
					                <MTab Value=3>    代码示例    </MTab>
 | 
				
			||||||
 | 
					            </MTabs>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <MTabsItems Value="tab">
 | 
				
			||||||
 | 
					                <MTabItem Value="1">
 | 
				
			||||||
 | 
					                    @if (tab == 1)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        @if (ReadWriteContent == null)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <div class="my-1 py-1">
 | 
				
			||||||
 | 
					                                <MTooltip Bottom Context="tip">
 | 
				
			||||||
 | 
					                                    <ActivatorContent>
 | 
				
			||||||
 | 
					                                        <MTextarea Class="mx-1 my-1" Label="变量地址" @attributes="@tip.Attrs" Dense Outlined HideDetails="@("auto")" @bind-Value=@Address />
 | 
				
			||||||
 | 
					                                    </ActivatorContent>
 | 
				
			||||||
 | 
					                                    <ChildContent>
 | 
				
			||||||
 | 
					                                        <span style="white-space: pre-wrap;">@Plc?.GetAddressDescription()</span>
 | 
				
			||||||
 | 
					                                    </ChildContent>
 | 
				
			||||||
 | 
					                                </MTooltip>
 | 
				
			||||||
 | 
					                                <MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters>
 | 
				
			||||||
 | 
					                                <MTextField Class="mx-1 my-1" Style="max-width:200px" Label="读取长度" Dense Outlined HideDetails="@("auto")" @bind-Value=@Length />
 | 
				
			||||||
 | 
					                                    <MSelect Class="mx-1 my-1" Style="max-width:200px" @bind-Value="DataTypeEnum" Outlined Label="数据类型"
 | 
				
			||||||
 | 
					                                             Items=@(typeof(DataTypeEnum).GetEnumListWithOutSugar())
 | 
				
			||||||
 | 
					                                             MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
 | 
				
			||||||
 | 
					                                             ItemText=@((u) =>u.Description)
 | 
				
			||||||
 | 
					                                             ItemValue=@(u =>(DataTypeEnum)u.Value)
 | 
				
			||||||
 | 
					                                             HideDetails=@("auto") Height="30"
 | 
				
			||||||
 | 
					                                              Dense>
 | 
				
			||||||
 | 
					                                </MSelect>
 | 
				
			||||||
 | 
					                            </MRow>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <MButton Class="mx-1 my-1" Color="primary" OnClick="ReadAsync">
 | 
				
			||||||
 | 
					                                读取
 | 
				
			||||||
 | 
					                            </MButton>
 | 
				
			||||||
 | 
					                            <MTextarea Class="mx-1 mt-3 my-1" Label="值" Dense Outlined HideDetails="@("auto")" @bind-Value=@WriteValue />
 | 
				
			||||||
 | 
					                                <MButton Class="mx-1 my-1" Color="primary" OnClick="WriteAsync">
 | 
				
			||||||
 | 
					                                    写入
 | 
				
			||||||
 | 
					                                </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            @ReadWriteContent
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                </MTabItem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <MTabItem Value="2">
 | 
				
			||||||
 | 
					                    @if (tab == 2)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        @if (ShowDefaultOtherContent)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            <MSubheader>
 | 
				
			||||||
 | 
					                                连读打包
 | 
				
			||||||
 | 
					                            </MSubheader>
 | 
				
			||||||
 | 
					                            <MContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                @foreach (var item in DeviceVariableRunTimes)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    <MRow Dense Align="AlignTypes.Center">
 | 
				
			||||||
 | 
					                                        <MTextField Class="ma-1" Outlined Style="min-width:100px" Label=@(item.DescriptionWithOutSugar(x => x.VariableAddress)) Dense HideDetails="@("auto")" @bind-Value=@item.VariableAddress></MTextField>
 | 
				
			||||||
 | 
					                                        <MSelect Class="mx-1 my-1" Style="max-width:120px" @bind-Value="item.DataTypeEnum" Outlined Label=@(item.DescriptionWithOutSugar(x => x.DataTypeEnum))
 | 
				
			||||||
 | 
					                                                 Items=@(typeof(DataTypeEnum).GetEnumListWithOutSugar())
 | 
				
			||||||
 | 
					                                                 MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
 | 
				
			||||||
 | 
					                                                 ItemText=@((u) =>u.Description)
 | 
				
			||||||
 | 
					                                                 ItemValue=@(u =>(DataTypeEnum)u.Value)
 | 
				
			||||||
 | 
					                                                 HideDetails=@("auto") Height="30"
 | 
				
			||||||
 | 
					                                              Dense>
 | 
				
			||||||
 | 
					                                    </MSelect>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(item.DescriptionWithOutSugar(x => x.IntervalTime)) Dense HideDetails="@("auto")" @bind-Value=@item.IntervalTime></MTextField>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=实时值 Readonly ClearIcon="" Dense HideDetails="@("auto")" Value=item.Value?.ToJsonString()></MTextField>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    </MRow>
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                <MRow Dense>
 | 
				
			||||||
 | 
					                                <MTextField Class="ma-1" Outlined Style="max-width:100px" Label="打包长度" Dense HideDetails="@("auto")" @bind-Value=@MaxPack></MTextField>
 | 
				
			||||||
 | 
					                                    <MButton Class="ma-1" Color="primary" OnClick="MulReadAsync">
 | 
				
			||||||
 | 
					                                        读取
 | 
				
			||||||
 | 
					                                    </MButton>
 | 
				
			||||||
 | 
					                                </MRow>
 | 
				
			||||||
 | 
					                            </MContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        @if (OtherContent != null)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            <MSheet Style="height:100%;overflow-y:auto">
 | 
				
			||||||
 | 
					                                @OtherContent
 | 
				
			||||||
 | 
					                            </MSheet>
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                </MTabItem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <MTabItem Value="3">
 | 
				
			||||||
 | 
					                    @if (tab == 3)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        @if (CodeContent != null)
 | 
				
			||||||
 | 
					                            @CodeContent
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <MRow Align="AlignTypes.Center">
 | 
				
			||||||
 | 
					                                <MContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    <MItemGroup @bind-Value="_selected" Class="shrink mr-6" Mandatory>
 | 
				
			||||||
 | 
					                                    @{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            int index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        <MRow>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            @foreach (var item in Sections)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                <MItem Value="@(index++)">
 | 
				
			||||||
 | 
					                                                    <div>
 | 
				
			||||||
 | 
					                                                        <MButton IsActive="@context.Active" Icon OnClick="@context.Toggle">
 | 
				
			||||||
 | 
					                                                            <MIcon>mdi-record</MIcon>
 | 
				
			||||||
 | 
					                                                        </MButton>
 | 
				
			||||||
 | 
					                                                    </div>
 | 
				
			||||||
 | 
					                                                </MItem>
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        </MRow>
 | 
				
			||||||
 | 
					                                    </MItemGroup>
 | 
				
			||||||
 | 
					                                </MContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                <MCol>
 | 
				
			||||||
 | 
					                                    <MWindow Value="_selected" Vertical Class="elevation-1 grey lighten-5 rounded-b" Style=@($"height:450px;overflow:auto")>
 | 
				
			||||||
 | 
					                                        @{
 | 
				
			||||||
 | 
					                                            int index = 0;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        @foreach (var item in Sections)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            <MWindowItem Value="@(index++)">
 | 
				
			||||||
 | 
					                                                <AppCode RoundedTop0 Code="@item.Code" Language="@item.Language" />
 | 
				
			||||||
 | 
					                                            </MWindowItem>
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    </MWindow>
 | 
				
			||||||
 | 
					                                </MCol>
 | 
				
			||||||
 | 
					                            </MRow>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                </MTabItem>
 | 
				
			||||||
 | 
					            </MTabsItems>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </MCol>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <MCol Md="7">
 | 
				
			||||||
 | 
					            <MCard Style="overflow-y:auto;width:100%" Elevation="0" Flat Class="ml-4">
 | 
				
			||||||
 | 
					                <ConsoleTxt Messages="Messages" Height=500></ConsoleTxt>
 | 
				
			||||||
 | 
					            </MCard>
 | 
				
			||||||
 | 
					        </MCol>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </MRow>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</MCard>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@code {
 | 
				
			||||||
 | 
					    StringNumber tab;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,236 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using BlazorComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public partial class DriverDebugUIPage : DriverDebugUIBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// DeviceVariableRunTimes
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public List<DeviceVariableRunTime> DeviceVariableRunTimes;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// MaxPack
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public int MaxPack = 100;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// MulReadAsync
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public async Task MulReadAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var deviceVariableSourceReads = Plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(DeviceVariableRunTimes, MaxPack);
 | 
				
			||||||
 | 
					        foreach (var item in deviceVariableSourceReads)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = await Plc.ReadAsync(item.VariableAddress, item.Length);
 | 
				
			||||||
 | 
					            if (result.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    item.DeviceVariableRunTimes.PraseStructContent(Plc, result.Content);
 | 
				
			||||||
 | 
					                    Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + result.Content.ToHexString(' ')));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (Exception ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex.Message));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + result.Message));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private StringNumber _selected = 0;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Sections
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public List<(string Code, string Language)> Sections { get; set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// ShowDefaultOtherContent
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public bool ShowDefaultOtherContent { get; set; } = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DeviceVariableRunTimes = new()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                                new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40001",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                   new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40011",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                   new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40031",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                   new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40101",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        Sections.Add((
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					                /// <inheritdoc/>
 | 
				
			||||||
 | 
					                public class DeviceVariableSourceRead : IDeviceVariableSourceRead<DeviceVariableRunTime>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public TimerTick TimerTick { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public string VariableAddress { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public int Length { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public List<DeviceVariableRunTime> DeviceVariableRunTimes { get; set; } = new List<DeviceVariableRunTime>();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                /// <inheritdoc/>
 | 
				
			||||||
 | 
					                public class DeviceVariableRunTime : IDeviceVariableRunTime
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    [Description("读取间隔")]
 | 
				
			||||||
 | 
					                    public int IntervalTime { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    [Description("变量地址")]
 | 
				
			||||||
 | 
					                    public string VariableAddress { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public int Index { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public IThingsGatewayBitConverter ThingsGatewayBitConverter { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    [Description("数据类型")]
 | 
				
			||||||
 | 
					                    public DataTypeEnum DataTypeEnum { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    [Description("实时值")]
 | 
				
			||||||
 | 
					                    public object Value { get; set; }
 | 
				
			||||||
 | 
					                    /// <inheritdoc/>
 | 
				
			||||||
 | 
					                    public OperResult SetValue(object value)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Value = value;
 | 
				
			||||||
 | 
					                        return OperResult.CreateSuccessResult();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                public List<DeviceVariableRunTime> DeviceVariableRunTimes;
 | 
				
			||||||
 | 
					                                
 | 
				
			||||||
 | 
					                private static async Task ModbusClientAsync(IReadWrite plc)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                DeviceVariableRunTimes = new()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                                new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40001",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                   new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40011",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                   new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40031",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                   new DeviceVariableRunTime()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    DataTypeEnum=DataTypeEnum.Int16,
 | 
				
			||||||
 | 
					                                    VariableAddress="40101",
 | 
				
			||||||
 | 
					                                    IntervalTime=1000,
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 连读
 | 
				
			||||||
 | 
					                var deviceVariableSourceReads = Plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(DeviceVariableRunTimes, MaxPack);
 | 
				
			||||||
 | 
					                foreach (var item in deviceVariableSourceReads)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var result = await Plc.ReadAsync(item.VariableAddress, item.Length);
 | 
				
			||||||
 | 
					                    if (result.IsSuccess)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        item.DeviceVariableRunTimes.PraseStructContent(result.Content);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					""", "csharp"));
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 自定义模板
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public RenderFragment ReadWriteContent { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 自定义模板
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public RenderFragment OtherContent { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 自定义模板
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Parameter]
 | 
				
			||||||
 | 
					    public RenderFragment CodeContent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    ~DriverDebugUIPage()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public override IReadWrite Plc { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Plc?.SafeDispose();
 | 
				
			||||||
 | 
					        base.Dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="firstRender"></param>
 | 
				
			||||||
 | 
					    protected override void OnAfterRender(bool firstRender)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.OnAfterRender(firstRender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					@using BlazorComponent;
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
 | 
					@using System.IO.Ports;
 | 
				
			||||||
 | 
					@using Masa.Blazor
 | 
				
			||||||
 | 
					<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
 | 
				
			||||||
 | 
					    <div class="mb-4">通道配置</div>
 | 
				
			||||||
 | 
					    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
 | 
				
			||||||
 | 
					        <MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(serialProperty.DescriptionWithOutSugar(x => x.PortName)) Dense HideDetails="@("auto")" @bind-Value=@serialProperty.PortName />
 | 
				
			||||||
 | 
					        <MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(serialProperty.DescriptionWithOutSugar(x => x.BaudRate)) Dense HideDetails="@("auto")" @bind-Value=@serialProperty.BaudRate />
 | 
				
			||||||
 | 
					        <MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(serialProperty.DescriptionWithOutSugar(x => x.DataBits)) Dense HideDetails="@("auto")" @bind-Value=@serialProperty.DataBits />
 | 
				
			||||||
 | 
					        <MSelect Class="ma-1 " Style="max-width:200px" Outlined @bind-Value="serialProperty.Parity" Label="@(serialProperty.DescriptionWithOutSugar(x => x.Parity))"
 | 
				
			||||||
 | 
					                 Items=@(typeof(Parity).GetEnumListWithOutSugar())
 | 
				
			||||||
 | 
					                 MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
 | 
				
			||||||
 | 
					                 ItemText=@((u) =>u.Description)
 | 
				
			||||||
 | 
					                 ItemValue=@(u =>(Parity)u.Value)
 | 
				
			||||||
 | 
					                 HideDetails=@("auto") Height="30"
 | 
				
			||||||
 | 
					                 Dense>
 | 
				
			||||||
 | 
					        </MSelect>
 | 
				
			||||||
 | 
					        <MSelect Class="ma-1 " Style="max-width:200px" Outlined @bind-Value="serialProperty.StopBits" Label="@(serialProperty.DescriptionWithOutSugar(x => x.StopBits))"
 | 
				
			||||||
 | 
					                 Items=@(typeof(StopBits).GetEnumListWithOutSugar())
 | 
				
			||||||
 | 
					                 MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })"
 | 
				
			||||||
 | 
					                 ItemText=@((u) =>u.Description)
 | 
				
			||||||
 | 
					                 ItemValue=@(u =>(StopBits)u.Value)
 | 
				
			||||||
 | 
					                 HideDetails=@("auto") Height="30"
 | 
				
			||||||
 | 
					                 Dense>
 | 
				
			||||||
 | 
					        </MSelect>
 | 
				
			||||||
 | 
					        <MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
 | 
				
			||||||
 | 
					            连接
 | 
				
			||||||
 | 
					        </MButton>
 | 
				
			||||||
 | 
					        <MButton Class="ma-1" OnClick=@DisConnect Color="red">
 | 
				
			||||||
 | 
					            断开
 | 
				
			||||||
 | 
					        </MButton>
 | 
				
			||||||
 | 
					    </MRow>
 | 
				
			||||||
 | 
					</MCard>
 | 
				
			||||||
@@ -10,14 +10,10 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Serial;
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					 | 
				
			||||||
using TouchSocket.Core;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Blazor;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
public partial class SerialSessionPage
 | 
					public partial class SerialSessionPage : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 日志输出
 | 
					    /// 日志输出
 | 
				
			||||||
@@ -28,34 +24,28 @@ public partial class SerialSessionPage
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private readonly SerialProperty serialProperty = new();
 | 
					    private readonly SerialProperty serialProperty = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SerialsSession SerialsSession { get; set; } = new();
 | 
					    private SerialSession SerialSession { get; set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public void Dispose()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        SerialsSession.SafeDispose();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取对象
 | 
					    /// 获取对象
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public SerialsSession GetSerialSession()
 | 
					    public SerialSession GetSerialSession()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config?.Dispose();
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
        config = new TouchSocketConfig();
 | 
					        var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
        config.SetSerialProperty(serialProperty);
 | 
					        config.SetSerialProperty(serialProperty);
 | 
				
			||||||
        //载入配置
 | 
					        //载入配置
 | 
				
			||||||
        SerialsSession.Setup(config);
 | 
					        SerialSession.Setup(config);
 | 
				
			||||||
        return SerialsSession;
 | 
					        return SerialSession;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private async Task ConnectAsync()
 | 
					    private async Task ConnectAsync()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SerialsSession.Close();
 | 
					            SerialSession.Close();
 | 
				
			||||||
            await GetSerialSession().ConnectAsync();
 | 
					            await GetSerialSession().ConnectAsync();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -68,25 +58,49 @@ public partial class SerialSessionPage
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SerialsSession.Close();
 | 
					            SerialSession.Close();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            LogAction?.Invoke(LogLevel.Error, null, null, ex);
 | 
					            LogAction?.Invoke(LogLevel.Error, null, null, ex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override void OnInitialized()
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config ??= new TouchSocketConfig();
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					 | 
				
			||||||
        SerialsSession = new SerialsSession();
 | 
					 | 
				
			||||||
        SerialsSession.Setup(config);
 | 
					 | 
				
			||||||
        base.OnInitialized();
 | 
					        base.OnInitialized();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="firstRender"></param>
 | 
				
			||||||
 | 
					    protected override void OnAfterRender(bool firstRender)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (firstRender)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
 | 
					            LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
 | 
					            config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
 | 
					            SerialSession.Setup(config);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        base.OnAfterRender(firstRender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        SerialSession.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    internal void StateHasChangedAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StateHasChanged();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -10,21 +10,19 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
*@
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@namespace ThingsGateway.Blazor
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
@using BlazorComponent;
 | 
					@using BlazorComponent;
 | 
				
			||||||
@using Microsoft.AspNetCore.Components.Web;
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
@using System.IO.Ports;
 | 
					@using System.IO.Ports;
 | 
				
			||||||
@using System.Collections.Concurrent;
 | 
					@using System.Collections.Concurrent;
 | 
				
			||||||
@using ThingsGateway.Foundation;
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
@using ThingsGateway.Foundation.Serial;
 | 
					 | 
				
			||||||
@using Masa.Blazor
 | 
					@using Masa.Blazor
 | 
				
			||||||
@using TouchSocket.Core;
 | 
					<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
 | 
				
			||||||
@using TouchSocket.Sockets;
 | 
					    <div class="mb-4">通道配置</div>
 | 
				
			||||||
@implements IDisposable
 | 
					    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
 | 
				
			||||||
<MCard Class="pa-4" Flat Elevation="0" Rounded="false">
 | 
					
 | 
				
			||||||
    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Start">
 | 
					        <MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@IP />
 | 
				
			||||||
        <MTextField Class="ma-1" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@IP />
 | 
					        <MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@Port />
 | 
				
			||||||
        <MTextField Class="ma-1" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@Port />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
 | 
					        <MButton Class="ma-1" OnClick=@ConnectAsync Color="primary">
 | 
				
			||||||
            连接
 | 
					            连接
 | 
				
			||||||
@@ -33,7 +31,4 @@
 | 
				
			|||||||
            断开
 | 
					            断开
 | 
				
			||||||
        </MButton>
 | 
					        </MButton>
 | 
				
			||||||
    </MRow>
 | 
					    </MRow>
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</MCard>
 | 
					</MCard>
 | 
				
			||||||
@@ -10,17 +10,10 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using TouchSocket.Core;
 | 
					 | 
				
			||||||
using TouchSocket.Sockets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Blazor;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
public partial class TcpClientPage
 | 
					public partial class TcpClientPage : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 日志输出
 | 
					    /// 日志输出
 | 
				
			||||||
@@ -33,24 +26,17 @@ public partial class TcpClientPage
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private string IP = "127.0.0.1";
 | 
					    private string IP = "127.0.0.1";
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 端口
 | 
					    /// Port
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [Parameter]
 | 
					 | 
				
			||||||
    public int Port { get; set; } = 502;
 | 
					    public int Port { get; set; } = 502;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private TcpClientEx TcpClientEx { get; set; } = new();
 | 
					    private TcpClient TcpClient { get; set; } = new();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public void Dispose()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        TcpClientEx.SafeDispose();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private async Task ConnectAsync()
 | 
					    private async Task ConnectAsync()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            TcpClientEx.Close();
 | 
					            TcpClient.Close();
 | 
				
			||||||
            await GetTcpClient().ConnectAsync();
 | 
					            await GetTcpClient().ConnectAsync();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -64,7 +50,7 @@ public partial class TcpClientPage
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            TcpClientEx.Close();
 | 
					            TcpClient.Close();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -76,32 +62,55 @@ public partial class TcpClientPage
 | 
				
			|||||||
    /// 获取对象
 | 
					    /// 获取对象
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public TcpClientEx GetTcpClient()
 | 
					    public TcpClient GetTcpClient()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config ??= new TouchSocketConfig();
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					        var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
        config.SetRemoteIPHost(new IPHost(IP + ":" + Port));
 | 
					        config.SetRemoteIPHost(new IPHost(IP + ":" + Port));
 | 
				
			||||||
        //载入配置
 | 
					        //载入配置
 | 
				
			||||||
        TcpClientEx.Setup(config);
 | 
					        TcpClient.Setup(config);
 | 
				
			||||||
        return TcpClientEx;
 | 
					        return TcpClient;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override void OnInitialized()
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config?.Dispose();
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
        config = new TouchSocketConfig();
 | 
					
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					 | 
				
			||||||
        config.SetRemoteIPHost(new IPHost(IP + ":" + Port));
 | 
					 | 
				
			||||||
        TcpClientEx = new TcpClientEx();
 | 
					 | 
				
			||||||
        TcpClientEx.Setup(config);
 | 
					 | 
				
			||||||
        base.OnInitialized();
 | 
					        base.OnInitialized();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="firstRender"></param>
 | 
				
			||||||
 | 
					    protected override void OnAfterRender(bool firstRender)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (firstRender)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
 | 
					            LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
 | 
					            config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
 | 
					            config.SetRemoteIPHost(new IPHost(IP + ":" + Port));
 | 
				
			||||||
 | 
					            TcpClient.Setup(config);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        base.OnAfterRender(firstRender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
					    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        TcpClient.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal void StateHasChangedAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StateHasChanged();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -10,21 +10,20 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
*@
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@namespace ThingsGateway.Blazor
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
@using BlazorComponent;
 | 
					@using BlazorComponent;
 | 
				
			||||||
@using Microsoft.AspNetCore.Components.Web;
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
@using System.IO.Ports;
 | 
					@using System.IO.Ports;
 | 
				
			||||||
@using System.Collections.Concurrent;
 | 
					@using System.Collections.Concurrent;
 | 
				
			||||||
@using ThingsGateway.Foundation;
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
@using ThingsGateway.Foundation.Serial;
 | 
					 | 
				
			||||||
@using Masa.Blazor
 | 
					@using Masa.Blazor
 | 
				
			||||||
@using TouchSocket.Core;
 | 
					
 | 
				
			||||||
@using TouchSocket.Sockets;
 | 
					<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
 | 
				
			||||||
@implements IDisposable
 | 
					    <div class="mb-4">通道配置</div>
 | 
				
			||||||
<MCard Class="pa-4" Flat Elevation="0" Rounded="false">
 | 
					    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
 | 
				
			||||||
    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Start">
 | 
					
 | 
				
			||||||
        <MTextField Class="ma-1" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@ip />
 | 
					        <MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@ip />
 | 
				
			||||||
        <MTextField Class="ma-1" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@port />
 | 
					        <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 Class="ma-1" OnClick=@Connect Color="primary">
 | 
				
			||||||
            连接
 | 
					            连接
 | 
				
			||||||
@@ -32,8 +31,8 @@
 | 
				
			|||||||
        <MButton Class="ma-1" OnClick=@DisConnect Color="red">
 | 
					        <MButton Class="ma-1" OnClick=@DisConnect Color="red">
 | 
				
			||||||
            断开
 | 
					            断开
 | 
				
			||||||
        </MButton>
 | 
					        </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </MRow>
 | 
					    </MRow>
 | 
				
			||||||
 | 
					</MCard>
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</MCard>
 | 
					 | 
				
			||||||
@@ -10,13 +10,10 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using TouchSocket.Core;
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
using TouchSocket.Sockets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Blazor;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
public partial class TcpServerPage
 | 
					public partial class TcpServerPage : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 日志输出
 | 
					    /// 日志输出
 | 
				
			||||||
@@ -31,11 +28,6 @@ public partial class TcpServerPage
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private TcpService TcpServer { get; set; } = new();
 | 
					    private TcpService TcpServer { get; set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public void Dispose()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        TcpServer.SafeDispose();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    private void Connect()
 | 
					    private void Connect()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
@@ -68,30 +60,49 @@ public partial class TcpServerPage
 | 
				
			|||||||
    public TcpService GetTcpServer()
 | 
					    public TcpService GetTcpServer()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config ??= new TouchSocketConfig();
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					        var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
        config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) });
 | 
					        config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) });
 | 
				
			||||||
        //载入配置
 | 
					        //载入配置
 | 
				
			||||||
        TcpServer.Setup(config);
 | 
					        TcpServer.Setup(config);
 | 
				
			||||||
        return TcpServer;
 | 
					        return TcpServer;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    protected override void OnInitialized()
 | 
					    /// <param name="firstRender"></param>
 | 
				
			||||||
 | 
					    protected override void OnAfterRender(bool firstRender)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config?.Dispose();
 | 
					        if (firstRender)
 | 
				
			||||||
        config = new TouchSocketConfig();
 | 
					        {
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					            var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					            LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					            config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
        config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) });
 | 
					            config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) });
 | 
				
			||||||
        TcpServer = new TcpService();
 | 
					            TcpServer.Setup(config);
 | 
				
			||||||
        TcpServer.Setup(config);
 | 
					        }
 | 
				
			||||||
        base.OnInitialized();
 | 
					        base.OnAfterRender(firstRender);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
					    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        TcpServer.SafeDispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    internal void StateHasChangedAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StateHasChanged();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -10,21 +10,20 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
*@
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@namespace ThingsGateway.Blazor
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
@using BlazorComponent;
 | 
					@using BlazorComponent;
 | 
				
			||||||
@using Microsoft.AspNetCore.Components.Web;
 | 
					@using Microsoft.AspNetCore.Components.Web;
 | 
				
			||||||
@using System.IO.Ports;
 | 
					@using System.IO.Ports;
 | 
				
			||||||
@using System.Collections.Concurrent;
 | 
					@using System.Collections.Concurrent;
 | 
				
			||||||
@using ThingsGateway.Foundation;
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
@using ThingsGateway.Foundation.Serial;
 | 
					 | 
				
			||||||
@using Masa.Blazor
 | 
					@using Masa.Blazor
 | 
				
			||||||
@using TouchSocket.Core;
 | 
					
 | 
				
			||||||
@using TouchSocket.Sockets;
 | 
					<MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%">
 | 
				
			||||||
@implements IDisposable
 | 
					    <div class="mb-4">通道配置</div>
 | 
				
			||||||
<MCard Class="pa-4" Flat Elevation="0" Rounded="false">
 | 
					    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center">
 | 
				
			||||||
    <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Start">
 | 
					
 | 
				
			||||||
        <MTextField Class="ma-1" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@ip />
 | 
					        <MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@IP />
 | 
				
			||||||
        <MTextField Class="ma-1" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@port />
 | 
					        <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 Class="ma-1" OnClick=Connect Color="primary">
 | 
				
			||||||
            连接
 | 
					            连接
 | 
				
			||||||
@@ -32,8 +31,7 @@
 | 
				
			|||||||
        <MButton Class="ma-1" OnClick=DisConnect Color="red">
 | 
					        <MButton Class="ma-1" OnClick=DisConnect Color="red">
 | 
				
			||||||
            断开
 | 
					            断开
 | 
				
			||||||
        </MButton>
 | 
					        </MButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </MRow>
 | 
					    </MRow>
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</MCard>
 | 
					</MCard>
 | 
				
			||||||
@@ -10,10 +10,7 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using TouchSocket.Core;
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
using TouchSocket.Sockets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Blazor;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
public partial class UdpSessionPage : IDisposable
 | 
					public partial class UdpSessionPage : IDisposable
 | 
				
			||||||
@@ -24,18 +21,17 @@ public partial class UdpSessionPage : IDisposable
 | 
				
			|||||||
    public Action<LogLevel, object, string, Exception> LogAction;
 | 
					    public Action<LogLevel, object, string, Exception> LogAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private TouchSocketConfig config;
 | 
					    private TouchSocketConfig config;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
    private string ip = "127.0.0.1";
 | 
					    /// IP
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    private int port = 502;
 | 
					    public string IP = "127.0.0.1";
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Port
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public int Port = 502;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private UdpSession UdpSession { get; set; } = new();
 | 
					    private UdpSession UdpSession { get; set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public void Dispose()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        UdpSession.SafeDispose();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    private void Connect()
 | 
					    private void Connect()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
@@ -68,32 +64,50 @@ public partial class UdpSessionPage : IDisposable
 | 
				
			|||||||
    public UdpSession GetUdpSession()
 | 
					    public UdpSession GetUdpSession()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config ??= new TouchSocketConfig();
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					        var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
        config.SetRemoteIPHost(new IPHost(ip + ":" + port));
 | 
					        config.SetRemoteIPHost(new IPHost(IP + ":" + Port));
 | 
				
			||||||
        config.SetBindIPHost(new IPHost(0));
 | 
					        config.SetBindIPHost(new IPHost(0));
 | 
				
			||||||
        //载入配置
 | 
					        //载入配置
 | 
				
			||||||
        UdpSession.Setup(config);
 | 
					        UdpSession.Setup(config);
 | 
				
			||||||
        return UdpSession;
 | 
					        return UdpSession;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config ??= new TouchSocketConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="firstRender"></param>
 | 
				
			||||||
 | 
					    protected override void OnAfterRender(bool firstRender)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (firstRender)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace };
 | 
				
			||||||
 | 
					            LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace });
 | 
				
			||||||
 | 
					            config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
				
			||||||
 | 
					            config.SetRemoteIPHost(new IPHost(IP + ":" + Port));
 | 
				
			||||||
 | 
					            config.SetBindIPHost(new IPHost(0));
 | 
				
			||||||
 | 
					            UdpSession.Setup(config);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        base.OnAfterRender(firstRender);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    protected override void OnInitialized()
 | 
					    public void Dispose()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config?.Dispose();
 | 
					        UdpSession.SafeDispose();
 | 
				
			||||||
        config = new TouchSocketConfig();
 | 
					    }
 | 
				
			||||||
        var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
 | 
					    internal void StateHasChangedAsync()
 | 
				
			||||||
        LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
 | 
					    {
 | 
				
			||||||
        config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
 | 
					        StateHasChanged();
 | 
				
			||||||
        config.SetRemoteIPHost(new IPHost(ip + ":" + port));
 | 
					 | 
				
			||||||
        config.SetBindIPHost(new IPHost(0));
 | 
					 | 
				
			||||||
        UdpSession = new UdpSession();
 | 
					 | 
				
			||||||
        UdpSession.Setup(config);
 | 
					 | 
				
			||||||
        base.OnInitialized();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class DeviceVariableRunTime : IDeviceVariableRunTime
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    [Description("读取间隔")]
 | 
				
			||||||
 | 
					    public int IntervalTime { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    [Description("变量地址")]
 | 
				
			||||||
 | 
					    public string VariableAddress { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public int Index { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public IThingsGatewayBitConverter ThingsGatewayBitConverter { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    [Description("数据类型")]
 | 
				
			||||||
 | 
					    public DataTypeEnum DataTypeEnum { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    [Description("实时值")]
 | 
				
			||||||
 | 
					    public object Value { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public OperResult SetValue(object value, DateTime dateTime = default, bool isOnline = true)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Value = value;
 | 
				
			||||||
 | 
					        return OperResult.CreateSuccessResult();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class DeviceVariableSourceRead : IDeviceVariableSourceRead<IDeviceVariableRunTime>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public TimerTick TimerTick { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public string VariableAddress { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public int Length { get; set; }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public List<IDeviceVariableRunTime> DeviceVariableRunTimes { get; set; } = new List<IDeviceVariableRunTime>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global using System;
 | 
				
			||||||
 | 
					global using System.Threading;
 | 
				
			||||||
 | 
					global using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global using ThingsGateway.Components;
 | 
				
			||||||
 | 
					global using ThingsGateway.Foundation.Serial;
 | 
				
			||||||
 | 
					global using ThingsGateway.Foundation.Sockets;
 | 
				
			||||||
@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@page "/"
 | 
				
			||||||
 | 
					@layout BaseLayout
 | 
				
			||||||
 | 
					@inject NavigationManager NavigationManager
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Authorization;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@code {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="firstRender"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    protected override async Task OnAfterRenderAsync(bool firstRender)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (firstRender)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            NavigationManager.NavigateTo("index");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await base.OnAfterRenderAsync(firstRender);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@page "/index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="ml-2">
 | 
				
			||||||
 | 
					    <div class="my-6 ">
 | 
				
			||||||
 | 
					        <MLabel Class="text-h3" Color="primary">ThingsGateway</MLabel>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <strong class="text--lighten-1 text-h5 my-1">文档</strong>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="my-2 ml-4">
 | 
				
			||||||
 | 
					        <PCopyableText>
 | 
				
			||||||
 | 
					            https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					        </PCopyableText>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <strong class="text--lighten-1 text-h5 my-1">协议</strong>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="my-2 ml-4">
 | 
				
			||||||
 | 
					        <PCopyableText Text="https://gitee.com/diego2098/ThingsGateway/blob/master/LICENSE.zh">
 | 
				
			||||||
 | 
					            Apache-2.0开源协议
 | 
				
			||||||
 | 
					        </PCopyableText>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <strong class="text--lighten-1 text-h5 my-1">赞助</strong>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="my-2 ml-4">
 | 
				
			||||||
 | 
					        <PCopyableText Text="https://diego2098.gitee.io/thingsgateway-docs/docs/donate">
 | 
				
			||||||
 | 
					            ThingsGateway赞助途径
 | 
				
			||||||
 | 
					        </PCopyableText>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <strong class="text--lighten-1 text-h5 my-1">社区</strong>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="my-2 ml-4">
 | 
				
			||||||
 | 
					        <PCopyableText Text="605534569">
 | 
				
			||||||
 | 
					            QQ群:605534569
 | 
				
			||||||
 | 
					        </PCopyableText>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
 | 
					@inherits LayoutComponentBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<CascadingValue Value="IsMobile" Name="IsMobile">
 | 
				
			||||||
 | 
					    <MApp>
 | 
				
			||||||
 | 
					        <MErrorHandler>
 | 
				
			||||||
 | 
					            @Body
 | 
				
			||||||
 | 
					        </MErrorHandler>
 | 
				
			||||||
 | 
					    </MApp>
 | 
				
			||||||
 | 
					</CascadingValue>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@code {
 | 
				
			||||||
 | 
					    public bool IsMobile { get; set; }
 | 
				
			||||||
 | 
					    [Inject]
 | 
				
			||||||
 | 
					    public MasaBlazor MasaBlazor { get; set; }
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					        MasaBlazor.BreakpointChanged += BreakpointOnOnUpdate;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void BreakpointOnOnUpdate(object sender, BreakpointChangedEventArgs e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IsMobile = MasaBlazor.Breakpoint.Mobile;
 | 
				
			||||||
 | 
					        if (e.MobileChanged)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            StateHasChanged();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,34 +10,18 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
*@
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@namespace ThingsGateway.Admin.Blazor
 | 
					@namespace ThingsGateway.Foundation.Demo
 | 
				
			||||||
@using Masa.Blazor.Presets
 | 
					@using System.Text;
 | 
				
			||||||
@using ThingsGateway.Admin.Blazor.Core
 | 
					 | 
				
			||||||
@inherits LayoutComponentBase
 | 
					@inherits LayoutComponentBase
 | 
				
			||||||
@layout BaseLayout
 | 
					@layout BaseLayout
 | 
				
			||||||
@if (UserManager.UserId > 0)
 | 
					
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    <SysSignalR></SysSignalR>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
<PPageTabsProvider>
 | 
					<PPageTabsProvider>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <CascadingValue Value="@this" IsFixed>
 | 
					    <CascadingValue Value="@this" IsFixed>
 | 
				
			||||||
        <CascadingValue Value="@Changed" Name="Changed">
 | 
					        <CascadingValue Value="@Changed" Name="Changed">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <MNavigationDrawer Color="barcolor" @bind-Value="_drawerOpen" App Width="200">
 | 
					            <MNavigationDrawer Color="barcolor" @bind-Value="_drawerOpen" App Width="200">
 | 
				
			||||||
                @if (IsMobile)
 | 
					                <Logo CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT  CONFIG_TITLE=@CONFIG_TITLE HeightInt=@(IsMobile?BlazorResourceConst.AppBarHeight:BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight) />
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    <MSystemBar Color="barcolor" Height="@(BlazorResourceConst.PageTabsHeight)">
 | 
					 | 
				
			||||||
                        <MButton Icon OnClick=@(()=> _drawerOpen = !_drawerOpen)>
 | 
					 | 
				
			||||||
                            <MIcon>
 | 
					 | 
				
			||||||
                                mdi-close-thick
 | 
					 | 
				
			||||||
                            </MIcon>
 | 
					 | 
				
			||||||
                        </MButton>
 | 
					 | 
				
			||||||
                        <MSpacer />
 | 
					 | 
				
			||||||
                        <AppbarButtons />
 | 
					 | 
				
			||||||
                    </MSystemBar>
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                <Logo CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE HeightInt=@(IsMobile?BlazorResourceConst.AppBarHeight:BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight) />
 | 
					 | 
				
			||||||
                <AppList ClassString="overflow-y-auto" Routable
 | 
					                <AppList ClassString="overflow-y-auto" Routable
 | 
				
			||||||
                         StyleString=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight}px);")
 | 
					                         StyleString=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight}px);")
 | 
				
			||||||
                         Items="Navs" />
 | 
					                         Items="Navs" />
 | 
				
			||||||
@@ -48,18 +32,16 @@
 | 
				
			|||||||
                <MButton Class="mr-0" Icon Small=IsMobile OnClick=@(() => _drawerOpen = !_drawerOpen)>
 | 
					                <MButton Class="mr-0" Icon Small=IsMobile OnClick=@(() => _drawerOpen = !_drawerOpen)>
 | 
				
			||||||
                    <MIcon>mdi-menu</MIcon>
 | 
					                    <MIcon>mdi-menu</MIcon>
 | 
				
			||||||
                </MButton>
 | 
					                </MButton>
 | 
				
			||||||
                <AppBarItems CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE>
 | 
					 | 
				
			||||||
                </AppBarItems>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            </MAppBar>
 | 
					            </MAppBar>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <MMain Style=@($"{(!(IsMobile||_drawerOpen!=true)? "padding-left:200px;":"")}")>
 | 
					            <MMain Style=@($"{(!(IsMobile||_drawerOpen!=true)? "padding-left:200px;":"")}")>
 | 
				
			||||||
                <div class="full-width">
 | 
					                <div class="full-width">
 | 
				
			||||||
                    <PageTabs @ref="_pageTabs" />
 | 
					                    <PageTabs @ref="_pageTabs" PageTabItems="pageTabItems" />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <MDivider Center></MDivider>
 | 
					                <MDivider Center></MDivider>
 | 
				
			||||||
                <MCard Flat Class="overflow-y-auto overflow-x-hidden ma-auto pa-0 rounded-0" Style=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight+BlazorResourceConst.FooterHeight}px);")>
 | 
					                <MCard Flat Class="overflow-y-auto overflow-x-hidden ma-auto pa-0 rounded-0" Style=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight+BlazorResourceConst.FooterHeight}px);")>
 | 
				
			||||||
                    <PPageContainer PageTabs="@_pageTabs?.PPageTabs" SelfPatterns="@selfPatterns">
 | 
					                    <PPageContainer PageTabs="@_pageTabs?.PPageTabs">
 | 
				
			||||||
                        @Body
 | 
					                        @Body
 | 
				
			||||||
                    </PPageContainer>
 | 
					                    </PPageContainer>
 | 
				
			||||||
                </MCard>
 | 
					                </MCard>
 | 
				
			||||||
@@ -71,5 +53,25 @@
 | 
				
			|||||||
    </CascadingValue>
 | 
					    </CascadingValue>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</PPageTabsProvider>
 | 
					</PPageTabsProvider>
 | 
				
			||||||
 | 
					@code {
 | 
				
			||||||
 | 
					    bool Changed { get; set; }
 | 
				
			||||||
 | 
					    private bool? _drawerOpen = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private PageTabs _pageTabs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// IsMobile
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [CascadingParameter(Name = "IsMobile")]
 | 
				
			||||||
 | 
					    public bool IsMobile { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@code{
 | 
				
			||||||
 | 
					    private string CONFIG_COPYRIGHT = "Diego";
 | 
				
			||||||
 | 
					    private string CONFIG_COPYRIGHT_URL = "https://gitee.com/diego2098/ThingsGateway";
 | 
				
			||||||
 | 
					    private string CONFIG_TITLE = "ThingsGateway";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
@@ -0,0 +1,214 @@
 | 
				
			|||||||
 | 
					#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 System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public partial class MainLayout
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private List<NavItem> Navs { get; set; } = new();
 | 
				
			||||||
 | 
					    private List<PageTabItem> pageTabItems { get; set; } = new();
 | 
				
			||||||
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var dataString =
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					[
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Href": "/index",
 | 
				
			||||||
 | 
					    "Title": "<22><>ҳ"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "Modbus",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusRtu",
 | 
				
			||||||
 | 
					        "Title": "ModbusRtu"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusTcp",
 | 
				
			||||||
 | 
					        "Title": "ModbusTcp"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusRtuOverTcp",
 | 
				
			||||||
 | 
					        "Title": "ModbusRtuOverTcp"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusRtuOverUdp",
 | 
				
			||||||
 | 
					        "Title": "ModbusRtuOverUdp"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusUdp",
 | 
				
			||||||
 | 
					        "Title": "ModbusUdp"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusTcpDtu",
 | 
				
			||||||
 | 
					        "Title": "ModbusTcpDtu"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusTcpServer",
 | 
				
			||||||
 | 
					        "Title": "ModbusTcpServer"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ModbusSerialServer",
 | 
				
			||||||
 | 
					        "Title": "ModbusSerialServer"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "Siemens",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/S7_1500",
 | 
				
			||||||
 | 
					        "Title": "S7_1500"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/S7_1200",
 | 
				
			||||||
 | 
					        "Title": "S7_1200"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/S7_200",
 | 
				
			||||||
 | 
					        "Title": "S7_200"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/S7_200SMART",
 | 
				
			||||||
 | 
					        "Title": "S7_200SMART"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/S7_300",
 | 
				
			||||||
 | 
					        "Title": "S7_400"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/S7_400",
 | 
				
			||||||
 | 
					        "Title": "S7_400"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "DLT645",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/DLT645_2007",
 | 
				
			||||||
 | 
					        "Title": "DLT645_2007"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/DLT645_2007OverTcp",
 | 
				
			||||||
 | 
					        "Title": "DLT645_2007OverTcp"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "OPCDA",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/OPCDAClient",
 | 
				
			||||||
 | 
					        "Title": "OPCDAClient"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "OPCUA",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/OPCUAClient",
 | 
				
			||||||
 | 
					        "Title": "OPCUAClient"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""";
 | 
				
			||||||
 | 
					        Navs = dataString.FromJsonString<List<NavItem>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if Pro
 | 
				
			||||||
 | 
					        var dataStringPro =
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					[
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "ABCIP",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/ABCIPTCP",
 | 
				
			||||||
 | 
					        "Title": "ABCIPTCP"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "Omron",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/OmronFinsTcp",
 | 
				
			||||||
 | 
					        "Title": "OmronFinsTcp"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/OmronFinsUdp",
 | 
				
			||||||
 | 
					        "Title": "OmronFinsUdp"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "Secs",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/SecsTcp",
 | 
				
			||||||
 | 
					        "Title": "SecsTcp"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "TS550",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/TS550",
 | 
				
			||||||
 | 
					        "Title": "TS550"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "Vigor",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/VigorSerial",
 | 
				
			||||||
 | 
					        "Title": "VigorSerial"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/VigorSerialOverTcp",
 | 
				
			||||||
 | 
					        "Title": "VigorSerialOverTcp"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Title": "GasCustom",
 | 
				
			||||||
 | 
					    "Children": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/GasCustomSerial",
 | 
				
			||||||
 | 
					        "Title": "GasCustomSerial"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "Href": "/GasCustomSerialOverTcp",
 | 
				
			||||||
 | 
					        "Title": "GasCustomSerialOverTcp"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					""";
 | 
				
			||||||
 | 
					        Navs.AddRange(dataStringPro.FromJsonString<List<NavItem>>());
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        pageTabItems = Navs.PasePageTabItem();
 | 
				
			||||||
 | 
					        base.OnInitialized();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk.Razor">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<PropertyGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
 | 
				
			||||||
 | 
							<DefineConstants>Pro</DefineConstants>
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
						<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'">
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							<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" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsTcpDebugPage.razor.cs" Link="Pages\OmronFins\OmronFinsTcpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsUdpDebugPage.razor.cs" Link="Pages\OmronFins\OmronFinsUdpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsTcpDebugPage.razor" Link="Pages\OmronFins\OmronFinsTcpDebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsUdpDebugPage.razor" Link="Pages\OmronFins\OmronFinsUdpDebugPage.razor" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Omron\ThingsGateway.Foundation.Adapter.Omron.csproj" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Secs\Page\SecsHsmsTcpDebugPage.razor.cs" Link="Pages\Secs\SecsHsmsTcpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Secs\Page\SecsHsmsTcpDebugPage.razor" Link="Pages\Secs\SecsHsmsTcpDebugPage.razor" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Secs\ThingsGateway.Foundation.Adapter.Secs.csproj" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.TS550\Page\TS550DebugPage.razor.cs" Link="Pages\TS550\TS550DebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\PluginPro\ThingsGateway.Plugin.TS550\Page\TS550DebugPage.razor" Link="Pages\TS550\TS550DebugPage.razor" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.TS550\ThingsGateway.Foundation.Adapter.TS550.csproj" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialDebugPage.razor.cs" Link="Pages\Vigor\VigorSerialDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialOverTcpDebugPage.razor.cs" Link="Pages\Vigor\VigorSerialOverTcpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialDebugPage.razor" Link="Pages\Vigor\VigorSerialDebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialOverTcpDebugPage.razor" Link="Pages\Vigor\VigorSerialOverTcpDebugPage.razor" />
 | 
				
			||||||
 | 
							<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" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<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" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverUdpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverUdpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverUdpDebugPage.razor" Link="Pages\Modbus\ModbusRtuOverUdpDebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusSerialServerDebugPage.razor.cs" Link="Pages\Modbus\ModbusSerialServerDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusSerialServerDebugPage.razor" Link="Pages\Modbus\ModbusSerialServerDebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDebugPage.razor" Link="Pages\Modbus\ModbusTcpDebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpDtuDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDtuDebugPage.razor" Link="Pages\Modbus\ModbusTcpDtuDebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpServerDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpServerDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpServerDebugPage.razor" Link="Pages\Modbus\ModbusTcpServerDebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusUdpDebugPage.razor.cs" Link="Pages\Modbus\ModbusUdpDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusUdpDebugPage.razor" Link="Pages\Modbus\ModbusUdpDebugPage.razor" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientDebugPage.razor.cs" Link="Pages\OPCDA\OPCDAClientDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientPage.razor.cs" Link="Pages\OPCDA\OPCDAClientPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAImportVariable.razor.cs" Link="Pages\OPCDA\OPCDAImportVariable.razor.cs" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientDebugPage.razor" Link="Pages\OPCDA\OPCDAClientDebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientPage.razor" Link="Pages\OPCDA\OPCDAClientPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAImportVariable.razor" Link="Pages\OPCDA\OPCDAImportVariable.razor" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientDebugPage.razor" Link="Pages\OPCUA\OPCUAClientDebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientPage.razor" Link="Pages\OPCUA\OPCUAClientPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAImportVariable.razor" Link="Pages\OPCUA\OPCUAImportVariable.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientDebugPage.razor.cs" Link="Pages\OPCUA\OPCUAClientDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientPage.razor.cs" Link="Pages\OPCUA\OPCUAClientPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAImportVariable.razor.cs" Link="Pages\OPCUA\OPCUAImportVariable.razor.cs" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1200DebugPage.razor" Link="Pages\Siemens\S7_1200DebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1500DebugPage.razor" Link="Pages\Siemens\S7_1500DebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200DebugPage.razor" Link="Pages\Siemens\S7_200DebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200SMARTDebugPage.razor" Link="Pages\Siemens\S7_200SMARTDebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_300DebugPage.razor" Link="Pages\Siemens\S7_300DebugPage.razor" />
 | 
				
			||||||
 | 
							<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_400DebugPage.razor" Link="Pages\Siemens\S7_400DebugPage.razor" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1200DebugPage.razor.cs" Link="Pages\Siemens\S7_1200DebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1500DebugPage.razor.cs" Link="Pages\Siemens\S7_1500DebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200DebugPage.razor.cs" Link="Pages\Siemens\S7_200DebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200SMARTDebugPage.razor.cs" Link="Pages\Siemens\S7_200SMARTDebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_300DebugPage.razor.cs" Link="Pages\Siemens\S7_300DebugPage.razor.cs" />
 | 
				
			||||||
 | 
							<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_400DebugPage.razor.cs" Link="Pages\Siemens\S7_400DebugPage.razor.cs" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<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" />
 | 
				
			||||||
 | 
							<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<Content Update="wwwroot\**">
 | 
				
			||||||
 | 
								<CopyToOutputDirectory>Always</CopyToOutputDirectory>
 | 
				
			||||||
 | 
							</Content>
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					@*
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					*@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@using System.Net.Http
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Forms
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Routing
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web
 | 
				
			||||||
 | 
					@using Microsoft.AspNetCore.Components.Web.Virtualization
 | 
				
			||||||
 | 
					@using Microsoft.JSInterop
 | 
				
			||||||
 | 
					@using BlazorComponent
 | 
				
			||||||
 | 
					@using Masa.Blazor
 | 
				
			||||||
 | 
					@using Masa.Blazor.Presets
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation;
 | 
				
			||||||
 | 
					@using ThingsGateway.Components;
 | 
				
			||||||
 | 
					@using ThingsGateway.Core;
 | 
				
			||||||
 | 
					@using System.Net.Http.Json
 | 
				
			||||||
 | 
					@using System.IO;
 | 
				
			||||||
 | 
					@using System.Text.Json;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation.Serial;
 | 
				
			||||||
 | 
					@using ThingsGateway.Foundation.Sockets;
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.2 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 10 KiB  | 
@@ -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>
 | 
				
			||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
<Project>
 | 
					<Project>
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
 | 
							<Version>3.0.0.0</Version>
 | 
				
			||||||
		<Version>2.1.0.6</Version>
 | 
							<GenerateDocumentationFile>True</GenerateDocumentationFile>
 | 
				
			||||||
 | 
							<LangVersion>latest</LangVersion>
 | 
				
			||||||
 | 
							<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
		<Authors>Diego</Authors>
 | 
							<Authors>Diego</Authors>
 | 
				
			||||||
		<Product>ThingsGateway</Product>
 | 
							<Product>ThingsGateway</Product>
 | 
				
			||||||
		<Copyright>© 2023-present Diego</Copyright>
 | 
							<Copyright>© 2023-present Diego</Copyright>
 | 
				
			||||||
@@ -11,34 +13,30 @@
 | 
				
			|||||||
		<EmbedAllSources>true</EmbedAllSources>
 | 
							<EmbedAllSources>true</EmbedAllSources>
 | 
				
			||||||
		<RepositoryType>Gitee</RepositoryType>
 | 
							<RepositoryType>Gitee</RepositoryType>
 | 
				
			||||||
		<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
							<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
				
			||||||
		<PackageReadmeFile>./README.md</PackageReadmeFile>
 | 
							<PackageReadmeFile>README.md</PackageReadmeFile>
 | 
				
			||||||
 | 
							<PackageIcon>icon.png</PackageIcon>
 | 
				
			||||||
		<IncludeSymbols>true</IncludeSymbols>
 | 
							<IncludeSymbols>true</IncludeSymbols>
 | 
				
			||||||
		<SymbolPackageFormat>snupkg</SymbolPackageFormat>
 | 
							<SymbolPackageFormat>snupkg</SymbolPackageFormat>
 | 
				
			||||||
		<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
 | 
							<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
 | 
				
			||||||
		<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway-docs/</PackageProjectUrl>
 | 
							<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway-docs/</PackageProjectUrl>
 | 
				
			||||||
		<PackageIcon>icon.png</PackageIcon>
 | 
					 | 
				
			||||||
		<PackageTags>ThingsGateway;Diego;dotNET China;Blazor;设备采集;边缘网关</PackageTags>
 | 
							<PackageTags>ThingsGateway;Diego;dotNET China;Blazor;设备采集;边缘网关</PackageTags>
 | 
				
			||||||
		<PackageOutputPath>../../../nupkgs</PackageOutputPath>
 | 
					 | 
				
			||||||
		<SignAssembly>True</SignAssembly>
 | 
							<SignAssembly>True</SignAssembly>
 | 
				
			||||||
		<DelaySign>False</DelaySign>
 | 
							<DelaySign>False</DelaySign>
 | 
				
			||||||
		<AssemblyOriginatorKeyFile>..\..\..\..\snks\ThingsGateway.snk</AssemblyOriginatorKeyFile>
 | 
					 | 
				
			||||||
		<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
 | 
							<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
 | 
				
			||||||
 | 
							<PackageOutputPath>../../nupkgs</PackageOutputPath>
 | 
				
			||||||
 | 
							<AssemblyOriginatorKeyFile>../../../snks/ThingsGateway.snk</AssemblyOriginatorKeyFile>
 | 
				
			||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<DocumentationFile>$(MSBuildProjectName).xml</DocumentationFile>
 | 
					 | 
				
			||||||
	</PropertyGroup>
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
					 | 
				
			||||||
		<LangVersion>latest</LangVersion>
 | 
					 | 
				
			||||||
	</PropertyGroup>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<None Include="..\..\..\..\README.md" Pack="true" PackagePath="\" />
 | 
							<None Include="..\..\..\README.md" Pack="true" PackagePath="\" />
 | 
				
			||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
		<None Include="..\..\..\..\icon.png">
 | 
							<None Include="..\..\..\icon.png">
 | 
				
			||||||
			<Pack>True</Pack>
 | 
								<Pack>True</Pack>
 | 
				
			||||||
			<PackagePath></PackagePath>
 | 
								<PackagePath></PackagePath>
 | 
				
			||||||
		</None>
 | 
							</None>
 | 
				
			||||||
@@ -10,66 +10,47 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using BlazorComponent;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
namespace ThingsGateway.Admin.Blazor.Core;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// ListItem
 | 
					/// 控制码
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
/// <typeparam name="TItem"></typeparam>
 | 
					public enum ControlCode : byte
 | 
				
			||||||
public interface IAppItem<TItem>
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 子菜单
 | 
					    /// 读数据
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    List<TItem> Children { get; }
 | 
					    Read = 0x11,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 是否启用下划线
 | 
					    /// 读后续数据
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    bool Divider { get; set; }
 | 
					    ReadSub = 0x12,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 菜单头部标题
 | 
					    /// 读站号
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    string Heading { get; }
 | 
					    ReadStation = 0x13,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 链接
 | 
					    /// 写数据
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    string Href { get; set; }
 | 
					    Write = 0x14,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 图标
 | 
					    /// 写站号
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    string Icon { get; set; }
 | 
					    WriteStation = 0x15,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 菜单副标题
 | 
					    /// 广播校时
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    string SubTitle { get; set; }
 | 
					    BroadcastTime = 0x08,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 跳转方式
 | 
					    /// 冻结
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    string Target { get; set; }
 | 
					    Freeze = 0x16,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 菜单标题
 | 
					    /// 更新波特率
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    string Title { get; set; }
 | 
					    WriteBaudRate = 0x17,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 菜单值
 | 
					    /// 更新密码
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    StringNumber Value { get; set; }
 | 
					    WritePassword = 0x18,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 是否有子菜单
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    /// <returns></returns>
 | 
					 | 
				
			||||||
    bool HasChildren()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return Children is not null && Children.Any();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -10,11 +10,9 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
@@ -45,6 +43,22 @@ internal static class DLT645Helper
 | 
				
			|||||||
        return bytes;
 | 
					        return bytes;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static string Get2007ErrorMessage(byte buffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        string error = buffer switch
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            0x80 => "其他错误",
 | 
				
			||||||
 | 
					            0x40 => "费率数超",
 | 
				
			||||||
 | 
					            0x20 => "日时段数超",
 | 
				
			||||||
 | 
					            0x10 => "年时区数超",
 | 
				
			||||||
 | 
					            0x08 => "通信速率不能更改",
 | 
				
			||||||
 | 
					            0x04 => "密码错/未授权",
 | 
				
			||||||
 | 
					            0x02 => "无请求数据",
 | 
				
			||||||
 | 
					            _ => "其他错误",
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        return error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取返回的解析信息
 | 
					    /// 获取返回的解析信息
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -1134,7 +1148,6 @@ internal static class DLT645Helper
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    internal static OperResult<byte[]> GetDLT645_2007Command(
 | 
					    internal static OperResult<byte[]> GetDLT645_2007Command(
 | 
				
			||||||
      string address,
 | 
					      string address,
 | 
				
			||||||
      int length,
 | 
					 | 
				
			||||||
      byte control,
 | 
					      byte control,
 | 
				
			||||||
      string defaultStation,
 | 
					      string defaultStation,
 | 
				
			||||||
      byte[] codes = null,
 | 
					      byte[] codes = null,
 | 
				
			||||||
@@ -1145,12 +1158,8 @@ internal static class DLT645Helper
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            codes ??= new byte[0];
 | 
					            codes ??= new byte[0];
 | 
				
			||||||
            datas ??= new string[0];
 | 
					            datas ??= new string[0];
 | 
				
			||||||
            var operResult = DLT645_2007Address.ParseFrom(address, length);
 | 
					            var operResult = DLT645_2007Address.ParseFrom(address);
 | 
				
			||||||
            if (!operResult.IsSuccess)
 | 
					            var buffer = operResult.DataId;
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return operResult.Copy<byte[]>();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            var buffer = operResult.Content.DataId;
 | 
					 | 
				
			||||||
            if (buffer.Length > 0)
 | 
					            if (buffer.Length > 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var dataInfos = GetDataInfos(buffer);
 | 
					                var dataInfos = GetDataInfos(buffer);
 | 
				
			||||||
@@ -1210,7 +1219,7 @@ internal static class DLT645Helper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            byte[] stationBytes;
 | 
					            byte[] stationBytes;
 | 
				
			||||||
            if (operResult.Content.Station.Length == 0)
 | 
					            if (operResult.Station.Length == 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (defaultStation.IsNullOrEmpty()) defaultStation = string.Empty;
 | 
					                if (defaultStation.IsNullOrEmpty()) defaultStation = string.Empty;
 | 
				
			||||||
                if (defaultStation.Length < 12)
 | 
					                if (defaultStation.Length < 12)
 | 
				
			||||||
@@ -1219,7 +1228,7 @@ internal static class DLT645Helper
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                stationBytes = operResult.Content.Station;
 | 
					                stationBytes = operResult.Station;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return GetDLT645_2007Command(control, buffer, stationBytes);
 | 
					            return GetDLT645_2007Command(control, buffer, stationBytes);
 | 
				
			||||||
@@ -1231,25 +1240,6 @@ internal static class DLT645Helper
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    internal static string Get2007ErrorMessage(byte buffer)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        string error = buffer switch
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            0x80 => "其他错误",
 | 
					 | 
				
			||||||
            0x40 => "费率数超",
 | 
					 | 
				
			||||||
            0x20 => "日时段数超",
 | 
					 | 
				
			||||||
            0x10 => "年时区数超",
 | 
					 | 
				
			||||||
            0x08 => "通信速率不能更改",
 | 
					 | 
				
			||||||
            0x04 => "密码错/未授权",
 | 
					 | 
				
			||||||
            0x02 => "无请求数据",
 | 
					 | 
				
			||||||
            _ => "其他错误",
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        return error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    internal static OperResult<byte[]> GetDLT645_2007Command(byte control, byte[] buffer, byte[] stationBytes)
 | 
					    internal static OperResult<byte[]> GetDLT645_2007Command(byte control, byte[] buffer, byte[] stationBytes)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        buffer ??= new byte[0];
 | 
					        buffer ??= new byte[0];
 | 
				
			||||||
@@ -10,47 +10,33 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.ComponentModel;
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Byte;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// DLT645_2007
 | 
					/// DLT645_2007
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
					public class DLT645_2007 : ReadWriteDevicesSerialSessionBase
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// DLT645_2007
 | 
					    /// DLT645_2007
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="tcpClient"></param>
 | 
					    /// <param name="serialSession"></param>
 | 
				
			||||||
    public DLT645_2007OverTcp(TcpClientEx tcpClient) : base(tcpClient)
 | 
					    public DLT645_2007(SerialSession serialSession) : base(serialSession)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
 | 
					        ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
 | 
				
			||||||
        RegisterByteLength = 2;
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 组包缓存时间/ms
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    [Description("组包缓存时间ms")]
 | 
					 | 
				
			||||||
    public int CacheTimeout { get; set; } = 1000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 增加FE FE FE FE的报文头部
 | 
					    /// 增加FE FE FE FE的报文头部
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [Description("前导符报文头")]
 | 
					    [Description("前导符报文头")]
 | 
				
			||||||
    public bool EnableFEHead { get; set; }
 | 
					    public bool EnableFEHead { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 帧前时间ms
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    [Description("帧前时间ms")]
 | 
					 | 
				
			||||||
    public int FrameTime { get; set; }
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 写入需操作员代码
 | 
					    /// 写入需操作员代码
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -69,22 +55,68 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
    [Description("通讯地址")]
 | 
					    [Description("通讯地址")]
 | 
				
			||||||
    public string Station { get; set; }
 | 
					    public string Station { get; set; }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override string GetAddressDescription() => base.GetAddressDescription() + Environment.NewLine;
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var str = """
 | 
				
			||||||
 | 
					            查看附带文档或者相关资料,下面列举一下常见的数据标识地址 
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            地址                       说明                    
 | 
				
			||||||
 | 
					            -----------------------------------------
 | 
				
			||||||
 | 
					            02010100    A相电压
 | 
				
			||||||
 | 
					            02020100    A相电流
 | 
				
			||||||
 | 
					            02030000    瞬时总有功功率
 | 
				
			||||||
 | 
					            00000000    (当前)组合有功总电能
 | 
				
			||||||
 | 
					            00010000    (当前)正向有功总电能
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            """;
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default)
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command(address, length, (byte)ControlCode.Read, Station);
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                return (MessageBase)result.RequestInfo;
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<byte[]>(commandResult);
 | 
					                return new OperResult<byte[]>(commandResult);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
 | 
				
			||||||
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OperResult<byte[]>(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -93,23 +125,22 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override void SetDataAdapter()
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var dataHandleAdapter = new DLT645_2007DataHandleAdapter
 | 
					        var dataHandleAdapter = new DLT645_2007DataHandleAdapter
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            EnableFEHead = EnableFEHead
 | 
					            EnableFEHead = EnableFEHead
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        TcpClientEx.SetDataHandlingAdapter(dataHandleAdapter);
 | 
					        SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken token = default)
 | 
					    public override OperResult Write(string address, string value, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
            Password ??= string.Empty;
 | 
					            Password ??= string.Empty;
 | 
				
			||||||
            OperCode ??= string.Empty;
 | 
					            OperCode ??= string.Empty;
 | 
				
			||||||
            if (Password.Length < 8)
 | 
					            if (Password.Length < 8)
 | 
				
			||||||
@@ -118,15 +149,15 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                OperCode = OperCode.PadLeft(8, '0');
 | 
					                OperCode = OperCode.PadLeft(8, '0');
 | 
				
			||||||
            var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
 | 
					            var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
 | 
				
			||||||
            string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
					            string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command(address, 1, (byte)ControlCode.Write, Station, data, strArray);
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                return (MessageBase)result.RequestInfo;
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<byte[]>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -134,34 +165,67 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
            return new OperResult<byte[]>(ex);
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, byte value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, double value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, float value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, long value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, short value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, int value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					    public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            Password ??= string.Empty;
 | 
				
			||||||
 | 
					            OperCode ??= string.Empty;
 | 
				
			||||||
 | 
					            if (Password.Length < 8)
 | 
				
			||||||
 | 
					                Password = Password.PadLeft(8, '0');
 | 
				
			||||||
 | 
					            if (OperCode.Length < 8)
 | 
				
			||||||
 | 
					                OperCode = OperCode.PadLeft(8, '0');
 | 
				
			||||||
 | 
					            var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
 | 
				
			||||||
 | 
					            string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
				
			||||||
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
 | 
				
			||||||
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region 其他方法
 | 
					    #region 其他方法
 | 
				
			||||||
@@ -170,23 +234,23 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
    /// 广播校时
 | 
					    /// 广播校时
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="dateTime"></param>
 | 
					    /// <param name="dateTime"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public OperResult BroadcastTime(DateTime dateTime, CancellationToken token = default)
 | 
					    public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Connect(token);
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
            string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
 | 
					            string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().Reverse().ToArray(), "999999999999".ByHexStringToBytes());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().ToArray(), "999999999999".ByHexStringToBytes());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TcpClientEx.Send(commandResult.Content);
 | 
					                SerialSession.Send(commandResult.Content);
 | 
				
			||||||
                return OperResult.CreateSuccessResult();
 | 
					                return OperResult.CreateSuccessResult();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -200,20 +264,20 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
    /// 冻结
 | 
					    /// 冻结
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="dateTime"></param>
 | 
					    /// <param name="dateTime"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken token = default)
 | 
					    public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
 | 
					            string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
 | 
				
			||||||
            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
					            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
				
			||||||
            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
					            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().Reverse().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -222,12 +286,12 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -237,20 +301,22 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 读取通信地址
 | 
					    /// 读取通信地址
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken token = default)
 | 
					    public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -259,12 +325,12 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult<string>(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult<string>(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -275,17 +341,18 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 修改波特率
 | 
					    /// 修改波特率
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="baudRate"></param>
 | 
					    /// <param name="baudRate"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken token = default)
 | 
					    public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            byte baudRateByte;
 | 
					            byte baudRateByte;
 | 
				
			||||||
            switch (baudRate)
 | 
					            switch (baudRate)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -302,7 +369,7 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -310,12 +377,12 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -329,17 +396,17 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
    /// 更新通信地址
 | 
					    /// 更新通信地址
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="station"></param>
 | 
					    /// <param name="station"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken token = default)
 | 
					    public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -348,12 +415,12 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -368,17 +435,17 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
    /// <param name="level"></param>
 | 
					    /// <param name="level"></param>
 | 
				
			||||||
    /// <param name="oldPassword"></param>
 | 
					    /// <param name="oldPassword"></param>
 | 
				
			||||||
    /// <param name="newPassword"></param>
 | 
					    /// <param name="newPassword"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken token = default)
 | 
					    public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
					            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
				
			||||||
            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
					            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
				
			||||||
            string str = $"04000C{level:D2}";
 | 
					            string str = $"04000C{(level + 1):D2}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
 | 
				
			||||||
                str.ByHexStringToBytes().Reverse().ToArray()
 | 
					                str.ByHexStringToBytes().Reverse().ToArray()
 | 
				
			||||||
@@ -387,7 +454,7 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                , Station.ByHexStringToBytes().Reverse().ToArray());
 | 
					                , Station.ByHexStringToBytes().Reverse().ToArray());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -395,12 +462,12 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -409,8 +476,6 @@ public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// DLT645_2007Address
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class DLT645_2007Address : DeviceAddressBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public DLT645_2007Address()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 数据标识
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte[] DataId { get; set; } = new byte[0];
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 反转解析
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool Reverse { get; set; } = true;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号信息
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte[] Station { get; set; } = new byte[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 解析地址
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="address"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static DLT645_2007Address ParseFrom(string address)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DLT645_2007Address dLT645_2007Address = new();
 | 
				
			||||||
 | 
					        byte[] array;
 | 
				
			||||||
 | 
					        array = new byte[0];
 | 
				
			||||||
 | 
					        if (address.IndexOf(';') < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            array = address.ByHexStringToBytes().Reverse().ToArray();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            string[] strArray = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (int index = 0; index < strArray.Length; ++index)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (strArray[index].ToUpper().StartsWith("S="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var station = strArray[index].Substring(2);
 | 
				
			||||||
 | 
					                    if (station.IsNullOrEmpty()) station = string.Empty;
 | 
				
			||||||
 | 
					                    if (station.Length < 12)
 | 
				
			||||||
 | 
					                        station = station.PadLeft(12, '0');
 | 
				
			||||||
 | 
					                    dLT645_2007Address.Station = station.ByHexStringToBytes().Reverse().ToArray();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (strArray[index].Contains("r="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    dLT645_2007Address.Reverse = strArray[index].Substring(2).GetBoolValue();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (!strArray[index].Contains("="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    array = strArray[index].ByHexStringToBytes().Reverse().ToArray();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dLT645_2007Address.DataId = array;
 | 
				
			||||||
 | 
					        return dLT645_2007Address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string ToString()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StringBuilder stringGeter = new();
 | 
				
			||||||
 | 
					        if (Station.Length > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringGeter.Append("s=" + Station.Reverse().ToArray().ToHexString() + ";");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (DataId.Length > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringGeter.Append(DataId.Reverse().ToArray().ToHexString() + ";");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!Reverse)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringGeter.Append("s=" + Reverse.ToString() + ";");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return stringGeter.ToString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,10 +10,8 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Byte;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
@@ -40,6 +38,19 @@ public class DLT645_2007BitConverter : ThingsGatewayBitConverter
 | 
				
			|||||||
        return Convert.ToDouble(this.ToString(buffer, offset, buffer.Length));
 | 
					        return Convert.ToDouble(this.ToString(buffer, offset, buffer.Length));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override IThingsGatewayBitConverter CopyNew()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new DLT645_2007BitConverter(EndianType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DataFormat = DataFormat,
 | 
				
			||||||
 | 
					            BcdFormat = BcdFormat,
 | 
				
			||||||
 | 
					            Encoding = Encoding,
 | 
				
			||||||
 | 
					            IsStringReverseByteWord = IsStringReverseByteWord,
 | 
				
			||||||
 | 
					            Length = Length,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override string ToString(byte[] buffer)
 | 
					    public override string ToString(byte[] buffer)
 | 
				
			||||||
@@ -50,7 +61,7 @@ public class DLT645_2007BitConverter : ThingsGatewayBitConverter
 | 
				
			|||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override string ToString(byte[] buffer, int offset, int length)
 | 
					    public override string ToString(byte[] buffer, int offset, int length)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        buffer = buffer.SelectMiddle(offset, length);
 | 
					        buffer = buffer.RemoveBegin(offset);
 | 
				
			||||||
        buffer = buffer.BytesAdd(-0x33);
 | 
					        buffer = buffer.BytesAdd(-0x33);
 | 
				
			||||||
        var dataInfos = DLT645Helper.GetDataInfos(buffer);
 | 
					        var dataInfos = DLT645Helper.GetDataInfos(buffer);
 | 
				
			||||||
        StringBuilder stringBuilder = new();
 | 
					        StringBuilder stringBuilder = new();
 | 
				
			||||||
@@ -65,11 +76,11 @@ public class DLT645_2007BitConverter : ThingsGatewayBitConverter
 | 
				
			|||||||
                    content[0] = (byte)(content[0] - 0x80);
 | 
					                    content[0] = (byte)(content[0] - 0x80);
 | 
				
			||||||
                    if (dataInfo.Digtal == 0)//无小数点
 | 
					                    if (dataInfo.Digtal == 0)//无小数点
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        stringBuilder.AppendLine($"-{content.ToHexString()}");
 | 
					                        stringBuilder.Append($"-{content.ToHexString()}");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        stringBuilder.AppendLine((-(Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString());
 | 
					                        stringBuilder.Append((-(Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString());
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
@@ -89,15 +100,15 @@ public class DLT645_2007BitConverter : ThingsGatewayBitConverter
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (dataInfo.Digtal < 0)
 | 
					            if (dataInfo.Digtal < 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                stringBuilder.AppendLine($"{Encoding.ASCII.GetString(content)}");
 | 
					                stringBuilder.Append($"{Encoding.ASCII.GetString(content)}");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (dataInfo.Digtal == 0)//无小数点
 | 
					            else if (dataInfo.Digtal == 0)//无小数点
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                stringBuilder.AppendLine($"{content.ToHexString()}");
 | 
					                stringBuilder.Append($"{content.ToHexString()}");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                stringBuilder.AppendLine(((Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString());
 | 
					                stringBuilder.Append(((Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -12,7 +12,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using System.ComponentModel;
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Adapter.Modbus;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
@@ -97,7 +96,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                //校验错误
 | 
					                //校验错误
 | 
				
			||||||
                request.Message = "和校验错误";
 | 
					                request.Message = "和校验错误";
 | 
				
			||||||
                request.ResultCode = ResultCode.Fail;
 | 
					                request.ErrorCode = 999;
 | 
				
			||||||
                return FilterResult.Success;
 | 
					                return FilterResult.Success;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,12 +111,12 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (
 | 
					                if (
 | 
				
			||||||
                (response[headCodeIndex + 1] == 0xAA) &&
 | 
					                (send[sendHeadCodeIndex + 1] == 0xAA) &&
 | 
				
			||||||
                (response[headCodeIndex + 2] == 0xAA) &&
 | 
					                (send[sendHeadCodeIndex + 2] == 0xAA) &&
 | 
				
			||||||
                (response[headCodeIndex + 3] == 0xAA) &&
 | 
					                (send[sendHeadCodeIndex + 3] == 0xAA) &&
 | 
				
			||||||
                (response[headCodeIndex + 4] == 0xAA) &&
 | 
					                (send[sendHeadCodeIndex + 4] == 0xAA) &&
 | 
				
			||||||
                (response[headCodeIndex + 5] == 0xAA) &&
 | 
					                (send[sendHeadCodeIndex + 5] == 0xAA) &&
 | 
				
			||||||
                (response[headCodeIndex + 6] == 0xAA)
 | 
					                (send[sendHeadCodeIndex + 6] == 0xAA)
 | 
				
			||||||
                )//读写通讯地址例外
 | 
					                )//读写通讯地址例外
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,7 +124,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    request.Message = "返回地址不符合规则";
 | 
					                    request.Message = "返回地址不符合规则";
 | 
				
			||||||
                    request.ResultCode = ResultCode.Fail;
 | 
					                    request.ErrorCode = 999;
 | 
				
			||||||
                    return FilterResult.Success;
 | 
					                    return FilterResult.Success;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,7 +135,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
            if ((response[headCodeIndex + 8] != send[sendHeadCodeIndex + 8] + 0x80))//控制码不符合时,返回错误
 | 
					            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.ResultCode = ResultCode.Fail;
 | 
					                request.ErrorCode = 999;
 | 
				
			||||||
                return FilterResult.Success;
 | 
					                return FilterResult.Success;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -148,7 +147,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
                byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33);
 | 
					                byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33);
 | 
				
			||||||
                var error = DLT645Helper.Get2007ErrorMessage(byte1);
 | 
					                var error = DLT645Helper.Get2007ErrorMessage(byte1);
 | 
				
			||||||
                request.Message = "异常控制码:" + $"0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
 | 
					                request.Message = "异常控制码:" + $"0x{response[headCodeIndex + 8]:X2},错误信息:{error}";
 | 
				
			||||||
                request.ResultCode = ResultCode.Fail;
 | 
					                request.ErrorCode = 999;
 | 
				
			||||||
                return FilterResult.Success;
 | 
					                return FilterResult.Success;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,7 +168,7 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    request.Message = "返回数据标识不符合规则";
 | 
					                    request.Message = "返回数据标识不符合规则";
 | 
				
			||||||
                    request.ResultCode = ResultCode.Fail;
 | 
					                    request.ErrorCode = 999;
 | 
				
			||||||
                    return FilterResult.Success;
 | 
					                    return FilterResult.Success;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,13 +176,13 @@ public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            request.Content = response.RemoveBegin(headCodeIndex + 10).RemoveLast(response.Length + 2 - len - headCodeIndex);
 | 
					            request.Content = response.RemoveBegin(headCodeIndex + 10).RemoveLast(response.Length + 2 - len - headCodeIndex);
 | 
				
			||||||
            request.ResultCode = ResultCode.Success;
 | 
					            request.ErrorCode = 0;
 | 
				
			||||||
            return FilterResult.Success;
 | 
					            return FilterResult.Success;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            request.ResultCode = ResultCode.Error;
 | 
					            request.ErrorCode = 999;
 | 
				
			||||||
            return FilterResult.Success;
 | 
					            return FilterResult.Success;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
@@ -10,48 +10,33 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.ComponentModel;
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Byte;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
using ThingsGateway.Foundation.Serial;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// DLT645_2007
 | 
					/// DLT645_2007
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
					public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// DLT645_2007
 | 
					    /// DLT645_2007
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="serialSession"></param>
 | 
					    /// <param name="tcpClient"></param>
 | 
				
			||||||
    public DLT645_2007(SerialsSession serialSession) : base(serialSession)
 | 
					    public DLT645_2007OverTcp(TcpClient tcpClient) : base(tcpClient)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
 | 
					        ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
 | 
				
			||||||
        RegisterByteLength = 2;
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 组包缓存时间/ms
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    [Description("组包缓存时间ms")]
 | 
					 | 
				
			||||||
    public int CacheTimeout { get; set; } = 1000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 增加FE FE FE FE的报文头部
 | 
					    /// 增加FE FE FE FE的报文头部
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [Description("前导符报文头")]
 | 
					    [Description("前导符报文头")]
 | 
				
			||||||
    public bool EnableFEHead { get; set; }
 | 
					    public bool EnableFEHead { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 帧前时间ms
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    [Description("帧前时间ms")]
 | 
					 | 
				
			||||||
    public int FrameTime { get; set; }
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 写入需操作员代码
 | 
					    /// 写入需操作员代码
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -89,20 +74,49 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default)
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command(address, length, (byte)ControlCode.Read, Station);
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                return (MessageBase)result.RequestInfo;
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<byte[]>(commandResult);
 | 
					                return new OperResult<byte[]>(commandResult);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station);
 | 
				
			||||||
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OperResult<byte[]>(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -111,23 +125,22 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override void SetDataAdapter()
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var dataHandleAdapter = new DLT645_2007DataHandleAdapter
 | 
					        var dataHandleAdapter = new DLT645_2007DataHandleAdapter
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            EnableFEHead = EnableFEHead
 | 
					            EnableFEHead = EnableFEHead
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        SerialsSession.SetDataHandlingAdapter(dataHandleAdapter);
 | 
					        TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken token = default)
 | 
					    public override OperResult Write(string address, string value, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
            Password ??= string.Empty;
 | 
					            Password ??= string.Empty;
 | 
				
			||||||
            OperCode ??= string.Empty;
 | 
					            OperCode ??= string.Empty;
 | 
				
			||||||
            if (Password.Length < 8)
 | 
					            if (Password.Length < 8)
 | 
				
			||||||
@@ -136,15 +149,15 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                OperCode = OperCode.PadLeft(8, '0');
 | 
					                OperCode = OperCode.PadLeft(8, '0');
 | 
				
			||||||
            var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
 | 
					            var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
 | 
				
			||||||
            string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
					            string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command(address, 1, (byte)ControlCode.Write, Station, data, strArray);
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                return (MessageBase)result.RequestInfo;
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<byte[]>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -152,34 +165,67 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
            return new OperResult<byte[]>(ex);
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken);
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, byte value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, double value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, float value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, long value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, short value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, int value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
 | 
					    public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            Password ??= string.Empty;
 | 
				
			||||||
 | 
					            OperCode ??= string.Empty;
 | 
				
			||||||
 | 
					            if (Password.Length < 8)
 | 
				
			||||||
 | 
					                Password = Password.PadLeft(8, '0');
 | 
				
			||||||
 | 
					            if (OperCode.Length < 8)
 | 
				
			||||||
 | 
					                OperCode = OperCode.PadLeft(8, '0');
 | 
				
			||||||
 | 
					            var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
 | 
				
			||||||
 | 
					            string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
				
			||||||
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray);
 | 
				
			||||||
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region 其他方法
 | 
					    #region 其他方法
 | 
				
			||||||
@@ -188,23 +234,23 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
    /// 广播校时
 | 
					    /// 广播校时
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="dateTime"></param>
 | 
					    /// <param name="dateTime"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public OperResult BroadcastTime(DateTime dateTime, CancellationToken token = default)
 | 
					    public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Connect(token);
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
            string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
 | 
					            string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().Reverse().ToArray(), "999999999999".ByHexStringToBytes());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().Reverse().ToArray(), "999999999999".ByHexStringToBytes());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                SerialsSession.Send(commandResult.Content);
 | 
					                TcpClient.Send(commandResult.Content);
 | 
				
			||||||
                return OperResult.CreateSuccessResult();
 | 
					                return OperResult.CreateSuccessResult();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -218,20 +264,20 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
    /// 冻结
 | 
					    /// 冻结
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="dateTime"></param>
 | 
					    /// <param name="dateTime"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken token = default)
 | 
					    public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
 | 
					            string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
 | 
				
			||||||
            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
					            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
				
			||||||
            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
					            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().Reverse().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().Reverse().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -240,12 +286,12 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -255,20 +301,22 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 读取通信地址
 | 
					    /// 读取通信地址
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken token = default)
 | 
					    public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -277,12 +325,12 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult<string>(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult<string>(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -293,17 +341,18 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 修改波特率
 | 
					    /// 修改波特率
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="baudRate"></param>
 | 
					    /// <param name="baudRate"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken token = default)
 | 
					    public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            byte baudRateByte;
 | 
					            byte baudRateByte;
 | 
				
			||||||
            switch (baudRate)
 | 
					            switch (baudRate)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -320,7 +369,7 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -328,12 +377,12 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -347,17 +396,17 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
    /// 更新通信地址
 | 
					    /// 更新通信地址
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <param name="station"></param>
 | 
					    /// <param name="station"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken token = default)
 | 
					    public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
					            var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -366,12 +415,12 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -386,13 +435,13 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
    /// <param name="level"></param>
 | 
					    /// <param name="level"></param>
 | 
				
			||||||
    /// <param name="oldPassword"></param>
 | 
					    /// <param name="oldPassword"></param>
 | 
				
			||||||
    /// <param name="newPassword"></param>
 | 
					    /// <param name="newPassword"></param>
 | 
				
			||||||
    /// <param name="token"></param>
 | 
					    /// <param name="cancellationToken"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken token = default)
 | 
					    public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await ConnectAsync(token);
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
					            if (Station.IsNullOrEmpty()) Station = string.Empty;
 | 
				
			||||||
            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
					            if (Station.Length < 12) Station = Station.PadLeft(12, '0');
 | 
				
			||||||
@@ -405,7 +454,7 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                , Station.ByHexStringToBytes().Reverse().ToArray());
 | 
					                , Station.ByHexStringToBytes().Reverse().ToArray());
 | 
				
			||||||
            if (commandResult.IsSuccess)
 | 
					            if (commandResult.IsSuccess)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken);
 | 
				
			||||||
                var result1 = ((MessageBase)result.RequestInfo);
 | 
					                var result1 = ((MessageBase)result.RequestInfo);
 | 
				
			||||||
                if (result1.IsSuccess)
 | 
					                if (result1.IsSuccess)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -413,12 +462,12 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return OperResult.CreateFailedResult<string>(result1);
 | 
					                    return new OperResult(result1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OperResult.CreateFailedResult<string>(commandResult);
 | 
					                return new OperResult(commandResult);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -427,50 +476,6 @@ public class DLT645_2007 : ReadWriteDevicesSerialBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/// <summary>
 | 
					 | 
				
			||||||
/// 控制码
 | 
					 | 
				
			||||||
/// </summary>
 | 
					 | 
				
			||||||
public enum ControlCode : byte
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 读数据
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    Read = 0x11,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 读后续数据
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    ReadSub = 0x12,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 读站号
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    ReadStation = 0x13,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 写数据
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    Write = 0x14,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 写站号
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    WriteStation = 0x15,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 广播校时
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    BroadcastTime = 0x08,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 冻结
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    Freeze = 0x16,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 更新波特率
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    WriteBaudRate = 0x17,
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 更新密码
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    WritePassword = 0x18,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -12,17 +12,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Application;
 | 
					namespace ThingsGateway.Foundation.Adapter.DLT645;
 | 
				
			||||||
using ThingsGateway.Foundation;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.DLT645;
 | 
					internal static class PackHelper
 | 
				
			||||||
 | 
					 | 
				
			||||||
internal static class DLT645_2007Helper
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    internal static List<DeviceVariableSourceRead> LoadSourceRead(this List<DeviceVariableRunTime> deviceVariables, IReadWriteDevice device)
 | 
					    public static List<T> LoadSourceRead<T, T2>(IReadWrite device, List<T2> deviceVariables, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var byteConverter = device.ThingsGatewayBitConverter;
 | 
					        var byteConverter = device.ThingsGatewayBitConverter;
 | 
				
			||||||
        var result = new List<DeviceVariableSourceRead>();
 | 
					        var result = new List<T>();
 | 
				
			||||||
        //需要先剔除额外信息,比如dataformat等
 | 
					        //需要先剔除额外信息,比如dataformat等
 | 
				
			||||||
        foreach (var item in deviceVariables)
 | 
					        foreach (var item in deviceVariables)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -30,13 +27,13 @@ internal static class DLT645_2007Helper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter);
 | 
					            IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter);
 | 
				
			||||||
            item.ThingsGatewayBitConverter = transformParameter;
 | 
					            item.ThingsGatewayBitConverter = transformParameter;
 | 
				
			||||||
            item.VariableAddress = address;
 | 
					            //item.VariableAddress = address;
 | 
				
			||||||
            item.Index = device.GetBitOffset(item.VariableAddress);
 | 
					            item.Index = device.GetBitOffset(item.VariableAddress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            result.Add(new()
 | 
					            result.Add(new()
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                DeviceVariables = new() { item },
 | 
					                DeviceVariableRunTimes = new() { item },
 | 
				
			||||||
                Address = address,
 | 
					                VariableAddress = address,
 | 
				
			||||||
                Length = 1,
 | 
					                Length = 1,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -15,5 +15,5 @@ global using System.Linq;
 | 
				
			|||||||
global using System.Threading;
 | 
					global using System.Threading;
 | 
				
			||||||
global using System.Threading.Tasks;
 | 
					global using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
global using TouchSocket.Core;
 | 
					global using ThingsGateway.Foundation.Serial;
 | 
				
			||||||
global using TouchSocket.Sockets;
 | 
					global using ThingsGateway.Foundation.Sockets;
 | 
				
			||||||
@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -41,27 +41,17 @@
 | 
				
			|||||||
            DLT645_2007
 | 
					            DLT645_2007
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.#ctor(ThingsGateway.Foundation.Serial.SerialsSession)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.#ctor(ThingsGateway.Foundation.Serial.SerialSession)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            DLT645_2007
 | 
					            DLT645_2007
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="serialSession"></param>
 | 
					            <param name="serialSession"></param>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.CacheTimeout">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            组包缓存时间/ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.EnableFEHead">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.EnableFEHead">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            增加FE FE FE FE的报文头部
 | 
					            增加FE FE FE FE的报文头部
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.OperCode">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.OperCode">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            写入需操作员代码
 | 
					            写入需操作员代码
 | 
				
			||||||
@@ -127,7 +117,7 @@
 | 
				
			|||||||
            广播校时
 | 
					            广播校时
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="dateTime"></param>
 | 
					            <param name="dateTime"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.FreezeAsync(System.DateTime,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.FreezeAsync(System.DateTime,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -135,14 +125,14 @@
 | 
				
			|||||||
            冻结
 | 
					            冻结
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="dateTime"></param>
 | 
					            <param name="dateTime"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadDeviceStationAsync(System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadDeviceStationAsync(System.Threading.CancellationToken)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            读取通信地址
 | 
					            读取通信地址
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -150,7 +140,7 @@
 | 
				
			|||||||
            修改波特率
 | 
					            修改波特率
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="baudRate"></param>
 | 
					            <param name="baudRate"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -158,7 +148,7 @@
 | 
				
			|||||||
            更新通信地址
 | 
					            更新通信地址
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="station"></param>
 | 
					            <param name="station"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -168,7 +158,7 @@
 | 
				
			|||||||
            <param name="level"></param>
 | 
					            <param name="level"></param>
 | 
				
			||||||
            <param name="oldPassword"></param>
 | 
					            <param name="oldPassword"></param>
 | 
				
			||||||
            <param name="newPassword"></param>
 | 
					            <param name="newPassword"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.DLT645.ControlCode">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.DLT645.ControlCode">
 | 
				
			||||||
@@ -271,7 +261,7 @@
 | 
				
			|||||||
            DLT645_2007
 | 
					            DLT645_2007
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.#ctor(TouchSocket.Core.EndianType)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.#ctor(ThingsGateway.Foundation.EndianType)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            DLT645_2007
 | 
					            DLT645_2007
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
@@ -314,27 +304,17 @@
 | 
				
			|||||||
            DLT645_2007
 | 
					            DLT645_2007
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.#ctor(ThingsGateway.Foundation.TcpClientEx)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.#ctor(ThingsGateway.Foundation.TcpClient)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            DLT645_2007
 | 
					            DLT645_2007
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="tcpClient"></param>
 | 
					            <param name="tcpClient"></param>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.CacheTimeout">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            组包缓存时间/ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.EnableFEHead">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.EnableFEHead">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            增加FE FE FE FE的报文头部
 | 
					            增加FE FE FE FE的报文头部
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.OperCode">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.OperCode">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            写入需操作员代码
 | 
					            写入需操作员代码
 | 
				
			||||||
@@ -400,7 +380,7 @@
 | 
				
			|||||||
            广播校时
 | 
					            广播校时
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="dateTime"></param>
 | 
					            <param name="dateTime"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.FreezeAsync(System.DateTime,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.FreezeAsync(System.DateTime,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -408,14 +388,14 @@
 | 
				
			|||||||
            冻结
 | 
					            冻结
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="dateTime"></param>
 | 
					            <param name="dateTime"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadDeviceStationAsync(System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadDeviceStationAsync(System.Threading.CancellationToken)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            读取通信地址
 | 
					            读取通信地址
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -423,7 +403,7 @@
 | 
				
			|||||||
            修改波特率
 | 
					            修改波特率
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="baudRate"></param>
 | 
					            <param name="baudRate"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -431,7 +411,7 @@
 | 
				
			|||||||
            更新通信地址
 | 
					            更新通信地址
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="station"></param>
 | 
					            <param name="station"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -441,7 +421,7 @@
 | 
				
			|||||||
            <param name="level"></param>
 | 
					            <param name="level"></param>
 | 
				
			||||||
            <param name="oldPassword"></param>
 | 
					            <param name="oldPassword"></param>
 | 
				
			||||||
            <param name="newPassword"></param>
 | 
					            <param name="newPassword"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message">
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#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.Linq;
 | 
				
			||||||
 | 
					global using System.Threading;
 | 
				
			||||||
 | 
					global using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global using ThingsGateway.Foundation.Serial;
 | 
				
			||||||
 | 
					global using ThingsGateway.Foundation.Sockets;
 | 
				
			||||||
@@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension;
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Modbus协议地址
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class ModbusAddress : DeviceAddressBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public ModbusAddress()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 读取功能码
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public ushort AddressStart => Address.ToUShort();
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 读取功能码
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte ReadFunction { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号信息
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte Station { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 写入功能码
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte WriteFunction { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 打包临时写入,需要读取的字节长度
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public int ByteLength { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// BitIndex
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public int BitIndex => (int)(Address.SplitDot().LastOrDefault().ToInt());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 读取功能码
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public ushort AddressEnd => (ushort)(AddressStart + (Math.Ceiling(ByteLength / 2.0) > 0 ? Math.Ceiling(ByteLength / 2.0) : 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 作为Slave时需提供的SocketId,用于分辨Socket客户端,通常对比的是初始链接时的注册包
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public string SocketId { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 解析地址
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static ModbusAddress ParseFrom(string address, byte station)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusAddress modbusAddress = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Station = station
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        return ParseFrom(address, modbusAddress);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 解析地址
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static ModbusAddress ParseFrom(string address, ModbusAddress modbusAddress = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        modbusAddress ??= new();
 | 
				
			||||||
 | 
					        if (address.IndexOf(';') < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Address(address);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            string[] strArray = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
 | 
				
			||||||
 | 
					            for (int index = 0; index < strArray.Length; ++index)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (strArray[index].ToUpper().StartsWith("S="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (Convert.ToInt16(strArray[index].Substring(2)) > 0)
 | 
				
			||||||
 | 
					                        modbusAddress.Station = byte.Parse(strArray[index].Substring(2));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (strArray[index].ToUpper().StartsWith("W="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (Convert.ToInt16(strArray[index].Substring(2)) > 0)
 | 
				
			||||||
 | 
					                        modbusAddress.WriteFunction = byte.Parse(strArray[index].Substring(2));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (strArray[index].ToUpper().StartsWith("ID="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    modbusAddress.SocketId = strArray[index].Substring(3);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (!strArray[index].Contains("="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Address(strArray[index]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return modbusAddress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void Address(string address)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var readF = ushort.Parse(address.Substring(0, 1));
 | 
				
			||||||
 | 
					            if (readF > 4)
 | 
				
			||||||
 | 
					                throw new("功能码错误");
 | 
				
			||||||
 | 
					            switch (readF)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case 0:
 | 
				
			||||||
 | 
					                    modbusAddress.ReadFunction = 1;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 1:
 | 
				
			||||||
 | 
					                    modbusAddress.ReadFunction = 2;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 3:
 | 
				
			||||||
 | 
					                    modbusAddress.ReadFunction = 4;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 4:
 | 
				
			||||||
 | 
					                    modbusAddress.ReadFunction = 3;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            modbusAddress.Address = (double.Parse(address.Substring(1)) - 1).ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string ToString()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StringBuilder stringGeter = new();
 | 
				
			||||||
 | 
					        if (Station > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringGeter.Append("s=" + Station.ToString() + ";");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (WriteFunction > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringGeter.Append("w=" + WriteFunction.ToString() + ";");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!string.IsNullOrEmpty(SocketId))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringGeter.Append("id=" + SocketId + ";");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        stringGeter.Append(GetFunctionString(ReadFunction) + (AddressStart + 1).ToString());
 | 
				
			||||||
 | 
					        return stringGeter.ToString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string GetFunctionString(int readF)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return readF switch
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            1 => "0",
 | 
				
			||||||
 | 
					            2 => "1",
 | 
				
			||||||
 | 
					            3 => "4",
 | 
				
			||||||
 | 
					            4 => "3",
 | 
				
			||||||
 | 
					            _ => "4",
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -13,7 +13,6 @@
 | 
				
			|||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Bool;
 | 
					using ThingsGateway.Foundation.Extension.Bool;
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Byte;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
@@ -130,8 +129,13 @@ internal class ModbusHelper
 | 
				
			|||||||
        if ((response.Length < response[2] + 5))
 | 
					        if ((response.Length < response[2] + 5))
 | 
				
			||||||
            return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
 | 
					            return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (response[2] == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if ((response.Length < 8))
 | 
				
			||||||
 | 
					                return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var data = response.SelectMiddle(0, response[2] + 5);
 | 
					        var data = response.SelectMiddle(0, response[2] != 0 ? response[2] + 5 : 8);
 | 
				
			||||||
        if (crcCheck && !EasyCRC16.CheckCRC16(data))
 | 
					        if (crcCheck && !EasyCRC16.CheckCRC16(data))
 | 
				
			||||||
            return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success };
 | 
					            return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success };
 | 
				
			||||||
        return GetModbusData(send, data.RemoveLast(2));
 | 
					        return GetModbusData(send, data.RemoveLast(2));
 | 
				
			||||||
@@ -143,8 +147,8 @@ internal class ModbusHelper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ModbusAddress mAddress = new(address, station);
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, station);
 | 
				
			||||||
            return GetReadModbusCommand(mAddress, length);
 | 
					            return OperResult.CreateSuccessResult(GetReadModbusCommand(mAddress, length));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -158,7 +162,8 @@ internal class ModbusHelper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ModbusAddress mAddress = new(address, station);
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, station);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //功能码或实际长度
 | 
					            //功能码或实际长度
 | 
				
			||||||
            if (values?.Length > 1 || mAddress.WriteFunction == 15)
 | 
					            if (values?.Length > 1 || mAddress.WriteFunction == 15)
 | 
				
			||||||
                return GetWriteBoolModbusCommand(mAddress, values, values.Length);
 | 
					                return GetWriteBoolModbusCommand(mAddress, values, values.Length);
 | 
				
			||||||
@@ -178,12 +183,13 @@ internal class ModbusHelper
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ModbusAddress mAddress = new(address, station);
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, station);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //功能码或实际长度
 | 
					            //功能码或实际长度
 | 
				
			||||||
            if (value?.Length > 2 || mAddress.WriteFunction == 16)
 | 
					            if (value?.Length > 2 || mAddress.WriteFunction == 16)
 | 
				
			||||||
                return GetWriteModbusCommand(mAddress, value);
 | 
					                return OperResult.CreateSuccessResult(GetWriteModbusCommand(mAddress, value));
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                return GetWriteOneModbusCommand(mAddress, value);
 | 
					                return OperResult.CreateSuccessResult(GetWriteOneModbusCommand(mAddress, value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
@@ -194,7 +200,7 @@ internal class ModbusHelper
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取读取报文
 | 
					    /// 获取读取报文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static OperResult<byte[]> GetReadModbusCommand(ModbusAddress mAddress, int length)
 | 
					    internal static byte[] GetReadModbusCommand(ModbusAddress mAddress, int length)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        byte[] array = new byte[6]
 | 
					        byte[] array = new byte[6]
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -205,21 +211,21 @@ internal class ModbusHelper
 | 
				
			|||||||
        BitConverter.GetBytes(length)[1],
 | 
					        BitConverter.GetBytes(length)[1],
 | 
				
			||||||
        BitConverter.GetBytes(length)[0]
 | 
					        BitConverter.GetBytes(length)[0]
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					        return array;
 | 
				
			||||||
        return OperResult.CreateSuccessResult(array);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取05写入布尔量报文
 | 
					    /// 获取05写入布尔量报文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station)
 | 
					    internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (address.IndexOf('.') <= 0)
 | 
					            if (address.IndexOf('.') <= 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ModbusAddress mAddress = new(address, station);
 | 
					                var mAddress = ModbusAddress.ParseFrom(address, station);
 | 
				
			||||||
                return GetWriteBoolModbusCommand(mAddress, value);
 | 
					
 | 
				
			||||||
 | 
					                return OperResult.CreateSuccessResult(GetWriteBoolModbusCommand(mAddress, value));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return new("不支持写入字寄存器的某一位");
 | 
					            return new("不支持写入字寄存器的某一位");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -232,7 +238,7 @@ internal class ModbusHelper
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取05写入布尔量报文
 | 
					    /// 获取05写入布尔量报文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value)
 | 
					    private static byte[] GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        byte[] array = new byte[6]
 | 
					        byte[] array = new byte[6]
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -253,13 +259,13 @@ internal class ModbusHelper
 | 
				
			|||||||
            array[4] = 0;
 | 
					            array[4] = 0;
 | 
				
			||||||
            array[5] = 0;
 | 
					            array[5] = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return OperResult.CreateSuccessResult(array);
 | 
					        return array;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取15写入布尔量报文
 | 
					    /// 获取15写入布尔量报文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length)
 | 
					    internal static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -284,7 +290,7 @@ internal class ModbusHelper
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取16写入字报文
 | 
					    /// 获取16写入字报文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static OperResult<byte[]> GetWriteModbusCommand(ModbusAddress mAddress, byte[] values)
 | 
					    internal static byte[] GetWriteModbusCommand(ModbusAddress mAddress, byte[] values)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        byte[] numArray = new byte[7 + values.Length];
 | 
					        byte[] numArray = new byte[7 + values.Length];
 | 
				
			||||||
        numArray[0] = (byte)mAddress.Station;
 | 
					        numArray[0] = (byte)mAddress.Station;
 | 
				
			||||||
@@ -295,14 +301,13 @@ internal class ModbusHelper
 | 
				
			|||||||
        numArray[5] = (byte)(values.Length / 2 % 256);
 | 
					        numArray[5] = (byte)(values.Length / 2 % 256);
 | 
				
			||||||
        numArray[6] = (byte)values.Length;
 | 
					        numArray[6] = (byte)values.Length;
 | 
				
			||||||
        values.CopyTo(numArray, 7);
 | 
					        values.CopyTo(numArray, 7);
 | 
				
			||||||
        return OperResult.CreateSuccessResult(numArray);
 | 
					        return numArray;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取6写入字报文
 | 
					    /// 获取6写入字报文
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private static OperResult<byte[]> GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values)
 | 
					    internal static byte[] GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        byte[] numArray = new byte[4 + values.Length];
 | 
					        byte[] numArray = new byte[4 + values.Length];
 | 
				
			||||||
        numArray[0] = (byte)mAddress.Station;
 | 
					        numArray[0] = (byte)mAddress.Station;
 | 
				
			||||||
@@ -310,7 +315,7 @@ internal class ModbusHelper
 | 
				
			|||||||
        numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
 | 
					        numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1];
 | 
				
			||||||
        numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
 | 
					        numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0];
 | 
				
			||||||
        values.CopyTo(numArray, 4);
 | 
					        values.CopyTo(numArray, 4);
 | 
				
			||||||
        return OperResult.CreateSuccessResult(numArray);
 | 
					        return numArray;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// ModbusRtu
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class ModbusRtu : ReadWriteDevicesSerialSessionBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// ModbusRtu
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="serialSession"></param>
 | 
				
			||||||
 | 
					    public ModbusRtu(SerialSession serialSession) : base(serialSession)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Crc校验
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("Crc校验")]
 | 
				
			||||||
 | 
					    public bool Crc16CheckEnable { get; set; } = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("站号")]
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusRtuDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Crc16CheckEnable = Crc16CheckEnable,
 | 
				
			||||||
 | 
					            CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        SerialSession.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            if (FrameTime != 0)
 | 
				
			||||||
 | 
					                Thread.Sleep(FrameTime);
 | 
				
			||||||
 | 
					            var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            await Task.Delay(FrameTime, cancellationToken);
 | 
				
			||||||
 | 
					            var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,7 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
@@ -46,13 +45,13 @@ public class ModbusRtuDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M
 | 
				
			|||||||
        var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
 | 
					        var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
 | 
				
			||||||
        if (result.IsSuccess)
 | 
					        if (result.IsSuccess)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            request.ResultCode = result.ResultCode;
 | 
					            request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
            request.Message = result.Message;
 | 
					            request.Message = result.Message;
 | 
				
			||||||
            request.Content = result.Content1;
 | 
					            request.Content = result.Content;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            request.ResultCode = result.ResultCode;
 | 
					            request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
            request.Message = result.Message;
 | 
					            request.Message = result.Message;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return result.Content2;
 | 
					        return result.Content2;
 | 
				
			||||||
@@ -0,0 +1,186 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class ModbusRtuOverTcp : ReadWriteDevicesTcpClientBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public ModbusRtuOverTcp(TcpClient tcpClient) : base(tcpClient)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Crc校验
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("Crc校验")]
 | 
				
			||||||
 | 
					    public bool Crc16CheckEnable { get; set; } = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("站号")]
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusRtuDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Crc16CheckEnable = Crc16CheckEnable,
 | 
				
			||||||
 | 
					            CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            if (FrameTime != 0)
 | 
				
			||||||
 | 
					                Thread.Sleep(FrameTime);
 | 
				
			||||||
 | 
					            var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            await Task.Delay(FrameTime, cancellationToken);
 | 
				
			||||||
 | 
					            var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,185 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class ModbusRtuOverUdp : ReadWriteDevicesUdpSessionBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public ModbusRtuOverUdp(UdpSession udpSession) : base(udpSession)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Crc校验
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("Crc校验")]
 | 
				
			||||||
 | 
					    public bool Crc16CheckEnable { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("站号")]
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusRtuOverUdpDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Crc16CheckEnable = Crc16CheckEnable,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        UdpSession.Config.SetUdpDataHandlingAdapter(() =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return dataHandleAdapter;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        UdpSession.Setup(UdpSession.Config);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            if (FrameTime != 0)
 | 
				
			||||||
 | 
					                Thread.Sleep(FrameTime);
 | 
				
			||||||
 | 
					            var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            await Task.Delay(FrameTime, cancellationToken);
 | 
				
			||||||
 | 
					            var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,8 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
@@ -37,10 +35,9 @@ public class ModbusRtuOverUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAd
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override OperResult<byte[]> UnpackResponse(
 | 
					    protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response)
 | 
				
			||||||
              byte[] send, byte[] response)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
 | 
					        var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable);
 | 
				
			||||||
        return result.Copy();
 | 
					        return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,421 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.Bool;
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SerialSession, OperResult> WriteData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 继电器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 开关输入
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 输入寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 保持寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new();
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public ModbusSerialServer(SerialSession serialSession) : base(serialSession)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 多站点
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool MulStation { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 默认站点
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach (var item in ModbusServer01ByteBlocks)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            item.Value.SafeDispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        foreach (var item in ModbusServer02ByteBlocks)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            item.Value.SafeDispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        foreach (var item in ModbusServer03ByteBlocks)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            item.Value.SafeDispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        foreach (var item in ModbusServer04ByteBlocks)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            item.Value.SafeDispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ModbusServer01ByteBlocks.Clear();
 | 
				
			||||||
 | 
					        ModbusServer02ByteBlocks.Clear();
 | 
				
			||||||
 | 
					        ModbusServer03ByteBlocks.Clear();
 | 
				
			||||||
 | 
					        ModbusServer04ByteBlocks.Clear();
 | 
				
			||||||
 | 
					        base.Dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <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)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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[]>("功能码错误");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(Read(address, length));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusSerialServerDataHandleAdapter dataHandleAdapter = new();
 | 
				
			||||||
 | 
					        dataHandleAdapter.CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout);
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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("功能码错误");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <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)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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("功能码错误");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(Write(address, value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(Write(address, value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void Received(ByteBlock byteBlock, IRequestInfo requestInfo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //接收外部报文
 | 
				
			||||||
 | 
					            if (requestInfo is ModbusSerialServerMessage modbusServerMessage)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (modbusServerMessage.CurModbusAddress == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return;//无法解析直接返回
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!modbusServerMessage.IsSuccess)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return;//无法解析直接返回
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.Length);
 | 
				
			||||||
 | 
					                    if (data.IsSuccess)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var coreData = data.Content;
 | 
				
			||||||
 | 
					                        if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling(modbusServerMessage.Length / 8.0));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 2).SpliceArray(new byte[] { (byte)coreData.Length }, coreData);
 | 
				
			||||||
 | 
					                        SerialSession.Send(sendData);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        WriteError(SerialSession, modbusServerMessage);//返回错误码
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else//写入
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var coreData = modbusServerMessage.Content;
 | 
				
			||||||
 | 
					                    if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //写入继电器
 | 
				
			||||||
 | 
					                        if (WriteData != null)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            // 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
				
			||||||
 | 
					                            if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
 | 
				
			||||||
 | 
					                                if (result.IsSuccess)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteSuccess03(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteError(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            //写入内存区
 | 
				
			||||||
 | 
					                            var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
 | 
				
			||||||
 | 
					                            if (result.IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteSuccess03(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //写入寄存器
 | 
				
			||||||
 | 
					                        if (WriteData != null)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
 | 
				
			||||||
 | 
					                                if (result.IsSuccess)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteSuccess03(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteError(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
 | 
				
			||||||
 | 
					                            if (result.IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteSuccess03(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(SerialSession, modbusServerMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Logger.LogError(ex, ToString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //返回错误码
 | 
				
			||||||
 | 
					        static void WriteError(SerialSession SerialSession, ModbusSerialServerMessage modbusServerMessage)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 2)
 | 
				
			||||||
 | 
					.SpliceArray(new byte[] { (byte)1 });//01 lllegal function
 | 
				
			||||||
 | 
					            sendData[1] = (byte)(sendData[1] + 128);
 | 
				
			||||||
 | 
					            SerialSession.Send(sendData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void WriteSuccess03(SerialSession SerialSession, ModbusSerialServerMessage modbusServerMessage)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 6);
 | 
				
			||||||
 | 
					        SerialSession.Send(sendData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class ModbusSerialServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusSerialServerMessage>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ThingsGatewayBitConverter ThingsGatewayBitConverter = new(EndianType.Big);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="command"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public override byte[] PackCommand(byte[] command)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ModbusHelper.AddCrc(command);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 获取modbus写入数据区内容
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="response">返回数据</param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal OperResult<byte[]> GetModbusData(byte[] response)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var func = ThingsGatewayBitConverter.ToByte(response, 1);
 | 
				
			||||||
 | 
					            if (func == 1 || func == 2 || func == 3 || func == 4 || func == 5 || func == 6)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (response.Length == 6)
 | 
				
			||||||
 | 
					                    return OperResult.CreateSuccessResult(response);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (func == 15 || func == 16)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var length = ThingsGatewayBitConverter.ToByte(response, 6);
 | 
				
			||||||
 | 
					                if (response.Length == 7 + length)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return OperResult.CreateSuccessResult(response);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>() { Message = $"数据长度{response.Length}错误" };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override ModbusSerialServerMessage GetInstance()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new ModbusSerialServerMessage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override FilterResult UnpackResponse(ModbusSerialServerMessage request, byte[] send, byte[] body, byte[] response)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var result1 = ModbusHelper.GetModbusRtuData(new byte[0], response, true);
 | 
				
			||||||
 | 
					        if (result1.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var result = GetModbusData(response.RemoveLast(2));
 | 
				
			||||||
 | 
					            if (result.IsSuccess)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                //解析01 03 00 00 00 0A
 | 
				
			||||||
 | 
					                var station = ThingsGatewayBitConverter.ToByte(response, 0);
 | 
				
			||||||
 | 
					                var function = ThingsGatewayBitConverter.ToByte(response, 1);
 | 
				
			||||||
 | 
					                int addressStart = ThingsGatewayBitConverter.ToInt16(response, 2);
 | 
				
			||||||
 | 
					                if (addressStart == -1)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    addressStart = 65535;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (function > 4)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (function > 6)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        request.CurModbusAddress = new ModbusAddress()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Station = station,
 | 
				
			||||||
 | 
					                            Address = addressStart.ToString(),
 | 
				
			||||||
 | 
					                            WriteFunction = function,
 | 
				
			||||||
 | 
					                            ReadFunction = (byte)(function == 16 ? 3 : function == 15 ? 1 : 3),
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                        request.Length = ThingsGatewayBitConverter.ToByte(response, 5);
 | 
				
			||||||
 | 
					                        request.Content = result.Content.RemoveBegin(7);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        request.CurModbusAddress = new ModbusAddress()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Station = station,
 | 
				
			||||||
 | 
					                            Address = addressStart.ToString(),
 | 
				
			||||||
 | 
					                            WriteFunction = function,
 | 
				
			||||||
 | 
					                            ReadFunction = (byte)(function == 6 ? 3 : function == 5 ? 1 : 3),
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                        request.Length = 1;
 | 
				
			||||||
 | 
					                        request.Content = result.Content.RemoveBegin(4);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    request.CurModbusAddress = new ModbusAddress()
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Station = station,
 | 
				
			||||||
 | 
					                        Address = addressStart.ToString(),
 | 
				
			||||||
 | 
					                        ReadFunction = function,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    request.Length = ThingsGatewayBitConverter.ToByte(response, 5);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
 | 
					                request.Message = result.Message;
 | 
				
			||||||
 | 
					                return FilterResult.Success;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
 | 
					                request.Message = result.Message;
 | 
				
			||||||
 | 
					                return FilterResult.Cache;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return result1.Content2;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class ModbusSerialServerMessage : MessageBase, IMessage
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 当前关联的地址
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public ModbusAddress CurModbusAddress { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 当前读写的数据长度
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public int Length { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override int HeadBytesLength => -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override bool CheckHeadBytes(byte[] head)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        BodyLength = -1;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void SendBytesThen()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,185 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class ModbusTcp : ReadWriteDevicesTcpClientBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public ModbusTcp(TcpClient tcpClient) : base(tcpClient)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 检测事务标识符
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("检测事务标识符")]
 | 
				
			||||||
 | 
					    public bool IsCheckMessageId { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("站号")]
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            var data = SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					            return data;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            var data = await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					            return data;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusTcpDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IsCheckMessageId = IsCheckMessageId,
 | 
				
			||||||
 | 
					            CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        TcpClient.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            if (FrameTime != 0)
 | 
				
			||||||
 | 
					                Thread.Sleep(FrameTime);
 | 
				
			||||||
 | 
					            var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            await Task.Delay(FrameTime, cancellationToken);
 | 
				
			||||||
 | 
					            var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -55,13 +55,13 @@ public class ModbusTcpDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M
 | 
				
			|||||||
        var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6));
 | 
					        var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6));
 | 
				
			||||||
        if (result.IsSuccess)
 | 
					        if (result.IsSuccess)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            request.ResultCode = result.ResultCode;
 | 
					            request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
            request.Message = result.Message;
 | 
					            request.Message = result.Message;
 | 
				
			||||||
            request.Content = result.Content1;
 | 
					            request.Content = result.Content;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            request.ResultCode = result.ResultCode;
 | 
					            request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
            request.Message = result.Message;
 | 
					            request.Message = result.Message;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return result.Content2;
 | 
					        return result.Content2;
 | 
				
			||||||
@@ -0,0 +1,259 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public ModbusTcpDtu(TcpService tcpService) : base(tcpService)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					        ModbusTcpDtuPlugin modbusTcpSalvePlugin = new ModbusTcpDtuPlugin();
 | 
				
			||||||
 | 
					        tcpService.Config.ConfigurePlugins(a =>
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					             a.Add(modbusTcpSalvePlugin);
 | 
				
			||||||
 | 
					         });
 | 
				
			||||||
 | 
					        tcpService.Setup(tcpService.Config);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 检测事务标识符
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("检测事务标识符")]
 | 
				
			||||||
 | 
					    public bool IsCheckMessageId { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("站号")]
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(mAddress.SocketId, commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(mAddress.SocketId, commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            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)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (socketClient is SocketClient client)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ModbusTcpDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                IsCheckMessageId = IsCheckMessageId,
 | 
				
			||||||
 | 
					                CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            client.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var item in TcpService.GetClients())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ModbusTcpDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    IsCheckMessageId = IsCheckMessageId,
 | 
				
			||||||
 | 
					                    CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                item.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(mAddress.SocketId, commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(mAddress.SocketId, commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(mAddress.SocketId, commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(mAddress.SocketId, commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OperResult<byte[]> SendThenReturn(string id, OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (TcpService.TryGetSocketClient($"ID={id}", out var client))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                SetDataAdapter(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var item = commandResult.Content;
 | 
				
			||||||
 | 
					                if (FrameTime != 0)
 | 
				
			||||||
 | 
					                    Thread.Sleep(FrameTime);
 | 
				
			||||||
 | 
					                var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true });
 | 
				
			||||||
 | 
					                var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OperResult<byte[]>("客户端未连接");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return commandResult;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<OperResult<byte[]>> SendThenReturnAsync(string id, OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (TcpService.TryGetSocketClient($"ID={id}", out var client))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                SetDataAdapter(client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var item = commandResult.Content;
 | 
				
			||||||
 | 
					                await Task.Delay(FrameTime, cancellationToken);
 | 
				
			||||||
 | 
					                var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true });
 | 
				
			||||||
 | 
					                var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					                return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OperResult<byte[]>("客户端未连接");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return commandResult;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class ModbusTcpDtuPlugin : PluginBase, ITcpReceivingPlugin
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public Task OnTcpReceiving(ITcpClientBase client, ByteBlockEventArgs e)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (client is ISocketClient socket)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!socket.Id.StartsWith("ID="))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ByteBlock byteBlock = e.ByteBlock;
 | 
				
			||||||
 | 
					                    var id = $"ID={byteBlock.ToArray().ToHexString()}";
 | 
				
			||||||
 | 
					                    socket.ResetId(id);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return e.InvokeNext();//如果本插件无法处理当前数据,请将数据转至下一个插件。
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -11,43 +11,44 @@
 | 
				
			|||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Bool;
 | 
					using ThingsGateway.Foundation.Extension.Bool;
 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Byte;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class ModbusServer : ReadWriteDevicesTcpServerBase
 | 
					public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 继电器
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    public ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 开关输入
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    public ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 输入寄存器
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    public ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// 保持寄存器
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    public ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new();
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
					    /// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SocketClient, OperResult> WriteData;
 | 
					    public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SocketClient, OperResult> WriteData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 继电器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 开关输入
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 输入寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 保持寄存器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new();
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public ModbusServer(TcpService tcpService) : base(tcpService)
 | 
					    public ModbusTcpServer(TcpService tcpService) : base(tcpService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
        RegisterByteLength = 2;
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
@@ -56,46 +57,18 @@ public class ModbusServer : ReadWriteDevicesTcpServerBase
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 多站点
 | 
					    /// 多站点
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("多站点")]
 | 
				
			||||||
    public bool MulStation { get; set; }
 | 
					    public bool MulStation { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 默认站点
 | 
					    /// 默认站点
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("默认站点")]
 | 
				
			||||||
    public byte Station { get; set; } = 1;
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override string GetAddressDescription()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default)
 | 
					    public override void Dispose()
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return Task.FromResult(Read(address, length));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override void SetDataAdapter(SocketClient client)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ModbusServerDataHandleAdapter dataHandleAdapter = new();
 | 
					 | 
				
			||||||
        client.SetDataHandlingAdapter(dataHandleAdapter);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken token = default)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return Task.FromResult(Write(address, value));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return Task.FromResult(Write(address, value));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <inheritdoc/>
 | 
					 | 
				
			||||||
    protected override void Dispose(bool disposing)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        foreach (var item in ModbusServer01ByteBlocks)
 | 
					        foreach (var item in ModbusServer01ByteBlocks)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -117,167 +90,28 @@ public class ModbusServer : ReadWriteDevicesTcpServerBase
 | 
				
			|||||||
        ModbusServer02ByteBlocks.Clear();
 | 
					        ModbusServer02ByteBlocks.Clear();
 | 
				
			||||||
        ModbusServer03ByteBlocks.Clear();
 | 
					        ModbusServer03ByteBlocks.Clear();
 | 
				
			||||||
        ModbusServer04ByteBlocks.Clear();
 | 
					        ModbusServer04ByteBlocks.Clear();
 | 
				
			||||||
        Disconnect();
 | 
					        base.Dispose();
 | 
				
			||||||
        base.Dispose(disposing);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override void Received(SocketClient client, IRequestInfo requestInfo)
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        //接收外部报文
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
        if (requestInfo is ModbusServerMessage modbusServerMessage)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (!modbusServerMessage.IsSuccess)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return;//无法解析直接返回
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (modbusServerMessage.CurModbusAddress == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                WriteError(client, modbusServerMessage);//无法解析变量地址,返回错误码
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.CurModbusAddress.Length);
 | 
					 | 
				
			||||||
                if (data.IsSuccess)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var coreData = data.Content;
 | 
					 | 
				
			||||||
                    if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling((double)modbusServerMessage.CurModbusAddress.Length / 8.0));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8)
 | 
					 | 
				
			||||||
                        .SpliceArray(new byte[] { (byte)coreData.Length }, coreData);
 | 
					 | 
				
			||||||
                    sendData[5] = (byte)(sendData.Length - 6);
 | 
					 | 
				
			||||||
                    client.Send(sendData);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    WriteError(client, modbusServerMessage);//返回错误码
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else//写入
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var coreData = modbusServerMessage.Content;
 | 
					 | 
				
			||||||
                if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    //写入继电器
 | 
					 | 
				
			||||||
                    if (WriteData != null)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        // 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
					 | 
				
			||||||
                        if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.CurModbusAddress.Length));
 | 
					 | 
				
			||||||
                            if (result.IsSuccess)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                WriteSuccess03(client, modbusServerMessage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            else
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                WriteError(client, modbusServerMessage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            WriteError(client, modbusServerMessage);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        //写入内存区
 | 
					 | 
				
			||||||
                        var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.CurModbusAddress.Length));
 | 
					 | 
				
			||||||
                        if (result.IsSuccess)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            WriteSuccess03(client, modbusServerMessage);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            WriteError(client, modbusServerMessage);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    //写入寄存器
 | 
					 | 
				
			||||||
                    if (WriteData != null)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
 | 
					 | 
				
			||||||
                            if (result.IsSuccess)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                WriteSuccess03(client, modbusServerMessage);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            else
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                WriteError(client, modbusServerMessage);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            WriteError(client, modbusServerMessage);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
 | 
					 | 
				
			||||||
                        if (result.IsSuccess)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            WriteSuccess03(client, modbusServerMessage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            WriteError(client, modbusServerMessage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //返回错误码
 | 
					 | 
				
			||||||
        static void WriteError(SocketClient client, ModbusServerMessage modbusServerMessage)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8)
 | 
					 | 
				
			||||||
.SpliceArray(new byte[] { (byte)1 });//01 lllegal function
 | 
					 | 
				
			||||||
            sendData[5] = (byte)(sendData.Length - 6);
 | 
					 | 
				
			||||||
            sendData[7] = (byte)(sendData[7] + 128);
 | 
					 | 
				
			||||||
            client.Send(sendData);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static void WriteSuccess03(SocketClient client, ModbusServerMessage modbusServerMessage)
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 12);
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
        sendData[5] = (byte)(sendData.Length - 6);
 | 
					 | 
				
			||||||
        client.Send(sendData);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    private OperResult<byte[]> Read(string address, int length)
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ModbusAddress mAddress;
 | 
					        ModbusAddress mAddress;
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            mAddress = new ModbusAddress(address, Station);
 | 
					            mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -328,12 +162,42 @@ public class ModbusServer : ReadWriteDevicesTcpServerBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return new OperResult<byte[]>("功能码错误");
 | 
					        return new OperResult<byte[]>("功能码错误");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private OperResult Write(string address, byte[] value)
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(Read(address, length));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (socketClient is SocketClient client)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ModbusTcpServerDataHandleAdapter dataHandleAdapter = new();
 | 
				
			||||||
 | 
					            dataHandleAdapter.CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout);
 | 
				
			||||||
 | 
					            client.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var item in TcpService.GetClients())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ModbusTcpDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout)
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                item.SetDataHandlingAdapter(dataHandleAdapter);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ModbusAddress mAddress;
 | 
					        ModbusAddress mAddress;
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            mAddress = new ModbusAddress(address, Station);
 | 
					            mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -366,12 +230,14 @@ public class ModbusServer : ReadWriteDevicesTcpServerBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return new OperResult("功能码错误");
 | 
					        return new OperResult("功能码错误");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private OperResult Write(string address, bool[] value)
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ModbusAddress mAddress;
 | 
					        ModbusAddress mAddress;
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            mAddress = new ModbusAddress(address, Station);
 | 
					            mAddress = ModbusAddress.ParseFrom(address, Station);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -407,4 +273,169 @@ public class ModbusServer : ReadWriteDevicesTcpServerBase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return new OperResult("功能码错误");
 | 
					        return new OperResult("功能码错误");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(Write(address, value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Task.FromResult(Write(address, value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    protected override void Received(SocketClient client, IRequestInfo requestInfo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //接收外部报文
 | 
				
			||||||
 | 
					            if (requestInfo is ModbusTcpServerMessage modbusServerMessage)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (modbusServerMessage.CurModbusAddress == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return;//无法解析直接返回
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!modbusServerMessage.IsSuccess)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return;//无法解析直接返回
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.Length);
 | 
				
			||||||
 | 
					                    if (data.IsSuccess)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var coreData = data.Content;
 | 
				
			||||||
 | 
					                        if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling(modbusServerMessage.Length / 8.0));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8).SpliceArray(new byte[] { (byte)coreData.Length }, coreData);
 | 
				
			||||||
 | 
					                        sendData[5] = (byte)(sendData.Length - 6);
 | 
				
			||||||
 | 
					                        client.Send(sendData);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        WriteError(client, modbusServerMessage);//返回错误码
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else//写入
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var coreData = modbusServerMessage.Content;
 | 
				
			||||||
 | 
					                    if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //写入继电器
 | 
				
			||||||
 | 
					                        if (WriteData != null)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            // 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
				
			||||||
 | 
					                            if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
 | 
				
			||||||
 | 
					                                if (result.IsSuccess)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteSuccess03(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteError(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            //写入内存区
 | 
				
			||||||
 | 
					                            var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
 | 
				
			||||||
 | 
					                            if (result.IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteSuccess03(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //写入寄存器
 | 
				
			||||||
 | 
					                        if (WriteData != null)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
 | 
				
			||||||
 | 
					                                if (result.IsSuccess)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteSuccess03(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    WriteError(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(client, modbusServerMessage);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData);
 | 
				
			||||||
 | 
					                            if (result.IsSuccess)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteSuccess03(client, modbusServerMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                WriteError(client, modbusServerMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Logger.LogError(ex, ToString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //返回错误码
 | 
				
			||||||
 | 
					        static void WriteError(SocketClient client, ModbusTcpServerMessage modbusServerMessage)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8)
 | 
				
			||||||
 | 
					.SpliceArray(new byte[] { (byte)1 });//01 lllegal function
 | 
				
			||||||
 | 
					            sendData[5] = (byte)(sendData.Length - 6);
 | 
				
			||||||
 | 
					            sendData[7] = (byte)(sendData[7] + 128);
 | 
				
			||||||
 | 
					            client.Send(sendData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void WriteSuccess03(SocketClient client, ModbusTcpServerMessage modbusServerMessage)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 12);
 | 
				
			||||||
 | 
					        sendData[5] = (byte)(sendData.Length - 6);
 | 
				
			||||||
 | 
					        client.Send(sendData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -15,7 +15,7 @@ using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			|||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <inheritdoc/>
 | 
					/// <inheritdoc/>
 | 
				
			||||||
public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusServerMessage>
 | 
					public class ModbusTcpServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusTcpServerMessage>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private readonly ThingsGatewayBitConverter ThingsGatewayBitConverter = new(EndianType.Big);
 | 
					    private readonly ThingsGatewayBitConverter ThingsGatewayBitConverter = new(EndianType.Big);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,7 +53,7 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new OperResult<byte[]>(response) { Message = $"数据长度{response.Length}错误" };
 | 
					            return new OperResult<byte[]>() { Message = $"数据长度{response.Length}错误" };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -62,13 +62,13 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override ModbusServerMessage GetInstance()
 | 
					    protected override ModbusTcpServerMessage GetInstance()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return new ModbusServerMessage();
 | 
					        return new ModbusTcpServerMessage();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override FilterResult UnpackResponse(ModbusServerMessage request, byte[] send, byte[] body, byte[] response)
 | 
					    protected override FilterResult UnpackResponse(ModbusTcpServerMessage request, byte[] send, byte[] body, byte[] response)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var result = GetModbusData(response.RemoveBegin(6));
 | 
					        var result = GetModbusData(response.RemoveBegin(6));
 | 
				
			||||||
        if (result.IsSuccess)
 | 
					        if (result.IsSuccess)
 | 
				
			||||||
@@ -88,11 +88,11 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
 | 
				
			|||||||
                    request.CurModbusAddress = new ModbusAddress()
 | 
					                    request.CurModbusAddress = new ModbusAddress()
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        Station = station,
 | 
					                        Station = station,
 | 
				
			||||||
                        AddressStart = addressStart,
 | 
					                        Address = addressStart.ToString(),
 | 
				
			||||||
                        WriteFunction = function,
 | 
					                        WriteFunction = function,
 | 
				
			||||||
                        ReadFunction = (byte)(function == 16 ? 3 : function == 15 ? 1 : 3),
 | 
					                        ReadFunction = (byte)(function == 16 ? 3 : function == 15 ? 1 : 3),
 | 
				
			||||||
                        Length = ThingsGatewayBitConverter.ToByte(response, 11),
 | 
					 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					                    request.Length = ThingsGatewayBitConverter.ToByte(response, 11);
 | 
				
			||||||
                    request.Content = result.Content.RemoveBegin(7);
 | 
					                    request.Content = result.Content.RemoveBegin(7);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
@@ -100,11 +100,11 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
 | 
				
			|||||||
                    request.CurModbusAddress = new ModbusAddress()
 | 
					                    request.CurModbusAddress = new ModbusAddress()
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        Station = station,
 | 
					                        Station = station,
 | 
				
			||||||
                        AddressStart = addressStart,
 | 
					                        Address = addressStart.ToString(),
 | 
				
			||||||
                        WriteFunction = function,
 | 
					                        WriteFunction = function,
 | 
				
			||||||
                        ReadFunction = (byte)(function == 6 ? 3 : function == 5 ? 1 : 3),
 | 
					                        ReadFunction = (byte)(function == 6 ? 3 : function == 5 ? 1 : 3),
 | 
				
			||||||
                        Length = 1,
 | 
					 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					                    request.Length = 1;
 | 
				
			||||||
                    request.Content = result.Content.RemoveBegin(4);
 | 
					                    request.Content = result.Content.RemoveBegin(4);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -113,18 +113,18 @@ public class ModbusServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte
 | 
				
			|||||||
                request.CurModbusAddress = new ModbusAddress()
 | 
					                request.CurModbusAddress = new ModbusAddress()
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    Station = station,
 | 
					                    Station = station,
 | 
				
			||||||
                    AddressStart = addressStart,
 | 
					                    Address = addressStart.ToString(),
 | 
				
			||||||
                    ReadFunction = function,
 | 
					                    ReadFunction = function,
 | 
				
			||||||
                    Length = ThingsGatewayBitConverter.ToByte(response, 11),
 | 
					 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					                request.Length = ThingsGatewayBitConverter.ToByte(response, 11);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            request.ResultCode = result.ResultCode;
 | 
					            request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
            request.Message = result.Message;
 | 
					            request.Message = result.Message;
 | 
				
			||||||
            return FilterResult.Success;
 | 
					            return FilterResult.Success;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            request.ResultCode = result.ResultCode;
 | 
					            request.ErrorCode = result.ErrorCode;
 | 
				
			||||||
            request.Message = result.Message;
 | 
					            request.Message = result.Message;
 | 
				
			||||||
            return FilterResult.Cache;
 | 
					            return FilterResult.Cache;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -15,12 +15,16 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public class ModbusServerMessage : MessageBase, IMessage
 | 
					    public class ModbusTcpServerMessage : MessageBase, IMessage
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 当前关联的地址
 | 
					        /// 当前关联的地址
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public ModbusAddress CurModbusAddress { get; set; }
 | 
					        public ModbusAddress CurModbusAddress { get; set; }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 当前读写的数据长度
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public int Length { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <inheritdoc/>
 | 
					        /// <inheritdoc/>
 | 
				
			||||||
        public override int HeadBytesLength => 6;
 | 
					        public override int HeadBytesLength => 6;
 | 
				
			||||||
@@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <inheritdoc/>
 | 
				
			||||||
 | 
					public class ModbusUdp : ReadWriteDevicesUdpSessionBase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public ModbusUdp(UdpSession udpSession) : base(udpSession)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
 | 
				
			||||||
 | 
					        RegisterByteLength = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 检测事务标识符
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("检测事务标识符")]
 | 
				
			||||||
 | 
					    public bool IsCheckMessageId { get; set; }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 站号
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Description("站号")]
 | 
				
			||||||
 | 
					    public byte Station { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string GetAddressDescription()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override void SetDataAdapter(object socketClient = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ModbusUdpDataHandleAdapter dataHandleAdapter = new()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IsCheckMessageId = IsCheckMessageId
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        UdpSession.Config.SetUdpDataHandlingAdapter(() =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return dataHandleAdapter;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        UdpSession.Setup(UdpSession.Config);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Connect(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return SendThenReturn(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await ConnectAsync(cancellationToken);
 | 
				
			||||||
 | 
					            var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station);
 | 
				
			||||||
 | 
					            return await SendThenReturnAsync(commandResult, cancellationToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult(ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            if (FrameTime != 0)
 | 
				
			||||||
 | 
					                Thread.Sleep(FrameTime);
 | 
				
			||||||
 | 
					            var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (commandResult.IsSuccess)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var item = commandResult.Content;
 | 
				
			||||||
 | 
					            await Task.Delay(FrameTime, cancellationToken);
 | 
				
			||||||
 | 
					            var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken);
 | 
				
			||||||
 | 
					            return (MessageBase)result.RequestInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new OperResult<byte[]>(commandResult.Message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,7 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Extension;
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension.Generic;
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
@@ -52,6 +51,6 @@ public class ModbusUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAdapter<M
 | 
				
			|||||||
    protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response)
 | 
					    protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6));
 | 
					        var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6));
 | 
				
			||||||
        return result.Copy();
 | 
					        return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,171 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.Generic;
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Extension.String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.Modbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// PackHelper
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class PackHelper
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 打包变量,添加到<see href="deviceVariableSourceReads"></see>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="device"></param>
 | 
				
			||||||
 | 
					    /// <param name="deviceVariables"></param>
 | 
				
			||||||
 | 
					    /// <param name="maxPack">最大打包长度</param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static List<T> LoadSourceRead<T, T2>(IReadWrite device, List<T2> deviceVariables, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (deviceVariables == null)
 | 
				
			||||||
 | 
					            throw new ArgumentNullException(nameof(deviceVariables));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var deviceVariableSourceReads = new List<T>();
 | 
				
			||||||
 | 
					        var byteConverter = device.ThingsGatewayBitConverter;
 | 
				
			||||||
 | 
					        //需要先剔除额外信息,比如dataformat等
 | 
				
			||||||
 | 
					        foreach (var item in deviceVariables)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var address = item.VariableAddress;
 | 
				
			||||||
 | 
					            IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter);
 | 
				
			||||||
 | 
					            item.ThingsGatewayBitConverter = transformParameter;
 | 
				
			||||||
 | 
					            //item.VariableAddress = address;
 | 
				
			||||||
 | 
					            item.Index = device.GetBitOffset(item.VariableAddress);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var deviceVariableRunTimeGroups = deviceVariables.GroupBy(it => it.IntervalTime);
 | 
				
			||||||
 | 
					        foreach (var group in deviceVariableRunTimeGroups)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Dictionary<ModbusAddress, T2> map = group.ToDictionary(it =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var lastLen = it.DataTypeEnum.GetByteLength();
 | 
				
			||||||
 | 
					                if (lastLen <= 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    switch (it.DataTypeEnum)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        case DataTypeEnum.String:
 | 
				
			||||||
 | 
					                            lastLen = it.ThingsGatewayBitConverter.Length == null ? throw new("数据类型为字符串时,必须指定字符串长度,才能进行打包") : it.ThingsGatewayBitConverter.Length.Value;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        default:
 | 
				
			||||||
 | 
					                            lastLen = 2;
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (it.ThingsGatewayBitConverter.Length != null && it.DataTypeEnum != DataTypeEnum.String)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    lastLen *= it.ThingsGatewayBitConverter.Length.Value;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var address = it.VariableAddress;
 | 
				
			||||||
 | 
					                if (address.IndexOf('.') > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var addressSplits = address.SplitDot();
 | 
				
			||||||
 | 
					                    address = addressSplits.RemoveLast(1).ArrayToString(".");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                var result = ModbusAddress.ParseFrom(address);
 | 
				
			||||||
 | 
					                result.ByteLength = lastLen;
 | 
				
			||||||
 | 
					                return result;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //获取变量的地址
 | 
				
			||||||
 | 
					            var modbusAddressList = map.Keys;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //获取功能码
 | 
				
			||||||
 | 
					            var functionCodes = modbusAddressList.Select(t => t.ReadFunction).Distinct();
 | 
				
			||||||
 | 
					            foreach (var functionCode in functionCodes)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var modbusAddressSameFunList = modbusAddressList.Where(t => t.ReadFunction == functionCode);
 | 
				
			||||||
 | 
					                var stationNumbers = modbusAddressSameFunList.Select(t => t.Station).Distinct();
 | 
				
			||||||
 | 
					                foreach (var stationNumber in stationNumbers)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var addressList = modbusAddressSameFunList
 | 
				
			||||||
 | 
					                        .Where(t => t.Station == stationNumber)
 | 
				
			||||||
 | 
					                        .ToDictionary(t => t, t => map[t]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var tempResult = LoadSourceRead<T, T2>(addressList, functionCode, group.Key, maxPack);
 | 
				
			||||||
 | 
					                    deviceVariableSourceReads.AddRange(tempResult);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return deviceVariableSourceReads;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static List<T> LoadSourceRead<T, T2>(Dictionary<ModbusAddress, T2> addressList, int functionCode, int intervalTime, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        List<T> sourceReads = new();
 | 
				
			||||||
 | 
					        //按地址和长度排序
 | 
				
			||||||
 | 
					        var orderByAddressEnd = addressList.Keys.OrderBy(it => it.AddressEnd);
 | 
				
			||||||
 | 
					        //按地址和长度排序
 | 
				
			||||||
 | 
					        var orderByAddressStart = addressList.Keys.OrderBy(it => it.AddressStart);
 | 
				
			||||||
 | 
					        //地址最小,在循环中更改
 | 
				
			||||||
 | 
					        var minAddress = orderByAddressStart.First().AddressStart;
 | 
				
			||||||
 | 
					        //地址最大
 | 
				
			||||||
 | 
					        var maxAddress = orderByAddressStart.Last().AddressStart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (maxAddress >= minAddress)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //最大的打包长度
 | 
				
			||||||
 | 
					            int readLength = maxPack;
 | 
				
			||||||
 | 
					            if (functionCode == 1 || functionCode == 2)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                readLength = maxPack * 8 * 2;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //获取当前的一组打包地址信息,
 | 
				
			||||||
 | 
					            var tempAddressEnd = orderByAddressEnd.Where(t => t.AddressEnd <= minAddress + readLength).ToList();
 | 
				
			||||||
 | 
					            //起始地址
 | 
				
			||||||
 | 
					            var startAddress = tempAddressEnd.OrderBy(it => it.AddressStart).First();
 | 
				
			||||||
 | 
					            //读取寄存器长度
 | 
				
			||||||
 | 
					            var sourceLen = tempAddressEnd.Last().AddressEnd - startAddress.AddressStart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            T sourceRead = new()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TimerTick = new TimerTick(intervalTime),
 | 
				
			||||||
 | 
					                //这里只需要根据地址排序的第一个地址,作为实际打包报文中的起始地址
 | 
				
			||||||
 | 
					                VariableAddress = startAddress.ToString(),
 | 
				
			||||||
 | 
					                Length = sourceLen
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            foreach (var item in tempAddressEnd)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var readNode = addressList[item];
 | 
				
			||||||
 | 
					                if ((functionCode == -1 || functionCode == 3 || functionCode == 4) && readNode.DataTypeEnum == DataTypeEnum.Boolean)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    readNode.Index = ((item.AddressStart - startAddress.AddressStart) * 16) + readNode.Index;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (functionCode == 1 || functionCode == 2)
 | 
				
			||||||
 | 
					                        readNode.Index = item.AddressStart - startAddress.AddressStart + readNode.Index;
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        readNode.Index = ((item.AddressStart - startAddress.AddressStart) * 2) + readNode.Index;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sourceRead.DeviceVariableRunTimes.Add(readNode);
 | 
				
			||||||
 | 
					                addressList.Remove(item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sourceReads.Add(sourceRead);
 | 
				
			||||||
 | 
					            if (orderByAddressEnd.Count() > 0)
 | 
				
			||||||
 | 
					                minAddress = orderByAddressStart.First().AddressStart;
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return sourceReads;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
						<ItemGroup>
 | 
				
			||||||
 | 
							<ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -14,11 +14,10 @@
 | 
				
			|||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.#ctor(System.String,System.UInt16)">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.AddressStart">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <summary>
 | 
				
			||||||
        </member>
 | 
					            读取功能码
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.#ctor(System.String,System.Byte)">
 | 
					            </summary>
 | 
				
			||||||
            <inheritdoc/>
 | 
					 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ReadFunction">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ReadFunction">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
@@ -35,16 +34,28 @@
 | 
				
			|||||||
            写入功能码
 | 
					            写入功能码
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.Parse(System.String,System.Int32)">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ByteLength">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            打包临时写入,需要读取的字节长度
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.AddressEnd">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            读取功能码
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.Parse(System.String)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ParseFrom(System.String,System.Int32)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ParseFrom(System.String,System.Byte)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            解析地址
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ParseFrom(System.String,ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            解析地址
 | 
					            解析地址
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="address"></param>
 | 
					 | 
				
			||||||
            <param name="length"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ToString">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ToString">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
@@ -135,24 +146,14 @@
 | 
				
			|||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.#ctor(ThingsGateway.Foundation.TcpClientEx)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.#ctor(ThingsGateway.Foundation.Sockets.TcpClient)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.CacheTimeout">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            组包缓存时间/ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Crc16CheckEnable">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Crc16CheckEnable">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            Crc校验
 | 
					            Crc校验
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Station">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Station">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            站号
 | 
					            站号
 | 
				
			||||||
@@ -161,10 +162,22 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.GetAddressDescription">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.GetAddressDescription">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Read(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.SetDataAdapter">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.SetDataAdapter(System.Object)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Write(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -173,13 +186,10 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.SendThenReturnAsync(ThingsGateway.Foundation.OperResult{System.Byte[]},System.Threading.CancellationToken)">
 | 
					 | 
				
			||||||
            <inheritdoc/>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.#ctor(TouchSocket.Sockets.UdpSession)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.#ctor(ThingsGateway.Foundation.Sockets.UdpSession)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Crc16CheckEnable">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Crc16CheckEnable">
 | 
				
			||||||
@@ -187,11 +197,6 @@
 | 
				
			|||||||
            Crc校验
 | 
					            Crc校验
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Station">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Station">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            站号
 | 
					            站号
 | 
				
			||||||
@@ -200,10 +205,22 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.GetAddressDescription">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.GetAddressDescription">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Read(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.SetDataAdapter">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.SetDataAdapter(System.Object)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Write(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -212,9 +229,6 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.SendThenReturnAsync(ThingsGateway.Foundation.OperResult{System.Byte[]},System.Threading.CancellationToken)">
 | 
					 | 
				
			||||||
            <inheritdoc/>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
@@ -239,27 +253,17 @@
 | 
				
			|||||||
            ModbusRtu
 | 
					            ModbusRtu
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.#ctor(ThingsGateway.Foundation.Serial.SerialsSession)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.#ctor(ThingsGateway.Foundation.Serial.SerialSession)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            ModbusRtu
 | 
					            ModbusRtu
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="serialSession"></param>
 | 
					            <param name="serialSession"></param>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.CacheTimeout">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            组包缓存时间/ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Crc16CheckEnable">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Crc16CheckEnable">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            Crc校验
 | 
					            Crc校验
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Station">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Station">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            站号
 | 
					            站号
 | 
				
			||||||
@@ -268,10 +272,22 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.GetAddressDescription">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.GetAddressDescription">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Read(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.SetDataAdapter">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.SetDataAdapter(System.Object)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Write(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Write(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -347,7 +363,7 @@
 | 
				
			|||||||
            接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
					            接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.#ctor(TouchSocket.Sockets.TcpService)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.#ctor(ThingsGateway.Foundation.Sockets.TcpService)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.MulStation">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.MulStation">
 | 
				
			||||||
@@ -360,13 +376,28 @@
 | 
				
			|||||||
            默认站点
 | 
					            默认站点
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Dispose">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.GetAddressDescription">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.GetAddressDescription">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Read(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.SetDataAdapter(TouchSocket.Sockets.SocketClient)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.SetDataAdapter(System.Object)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Write(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Write(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -375,10 +406,7 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Dispose(System.Boolean)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Received(ThingsGateway.Foundation.Sockets.SocketClient,ThingsGateway.Foundation.IRequestInfo)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Received(TouchSocket.Sockets.SocketClient,TouchSocket.Core.IRequestInfo)">
 | 
					 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter">
 | 
				
			||||||
@@ -414,6 +442,11 @@
 | 
				
			|||||||
            当前关联的地址
 | 
					            当前关联的地址
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.Length">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            当前读写的数据长度
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.HeadBytesLength">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.HeadBytesLength">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
@@ -423,19 +456,9 @@
 | 
				
			|||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.#ctor(ThingsGateway.Foundation.TcpClientEx)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.#ctor(ThingsGateway.Foundation.Sockets.TcpClient)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.CacheTimeout">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            组包缓存时间/ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.IsCheckMessageId">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.IsCheckMessageId">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            检测事务标识符
 | 
					            检测事务标识符
 | 
				
			||||||
@@ -449,10 +472,22 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.GetAddressDescription">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.GetAddressDescription">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Read(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.SetDataAdapter">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.SetDataAdapter(System.Object)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Write(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -461,9 +496,6 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.SendThenReturnAsync(ThingsGateway.Foundation.OperResult{System.Byte[]},System.Threading.CancellationToken)">
 | 
					 | 
				
			||||||
            <inheritdoc/>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            ModbusTcpDataHandleAdapter
 | 
					            ModbusTcpDataHandleAdapter
 | 
				
			||||||
@@ -502,14 +534,9 @@
 | 
				
			|||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.#ctor(TouchSocket.Sockets.UdpSession)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.#ctor(ThingsGateway.Foundation.Sockets.UdpSession)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.FrameTime">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            帧前时间ms
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.IsCheckMessageId">
 | 
					        <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.IsCheckMessageId">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            检测事务标识符
 | 
					            检测事务标识符
 | 
				
			||||||
@@ -520,13 +547,25 @@
 | 
				
			|||||||
            站号
 | 
					            站号
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.GetAddressDescription">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.GetAddressDescription">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Read(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.SetDataAdapter">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.SetDataAdapter(System.Object)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Write(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
 | 
					            <inheritdoc/>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)">
 | 
				
			||||||
@@ -535,9 +574,6 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.SendThenReturnAsync(ThingsGateway.Foundation.OperResult{System.Byte[]},System.Threading.CancellationToken)">
 | 
					 | 
				
			||||||
            <inheritdoc/>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter">
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
@@ -557,5 +593,19 @@
 | 
				
			|||||||
        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter.UnpackResponse(System.Byte[],System.Byte[])">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter.UnpackResponse(System.Byte[],System.Byte[])">
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="T:ThingsGateway.Foundation.Adapter.Modbus.PackHelper">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            PackHelper
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.Modbus.PackHelper.ModbusLoadSourceRead``2(ThingsGateway.Foundation.IReadWrite,System.Collections.Generic.List{``1},System.Int32)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            打包变量,添加到<see href="deviceVariableSourceReads"></see>
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="device"></param>
 | 
				
			||||||
 | 
					            <param name="deviceVariables"></param>
 | 
				
			||||||
 | 
					            <param name="MaxPack">最大打包长度</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
    </members>
 | 
					    </members>
 | 
				
			||||||
</doc>
 | 
					</doc>
 | 
				
			||||||
@@ -10,7 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Runtime.InteropServices;
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
					using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
				
			||||||
@@ -10,8 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.OPCDA.Da;
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCDA.Da;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
@@ -10,10 +10,7 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Runtime.InteropServices;
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
					using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -201,7 +198,7 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
        OnWriteCompleted?.Invoke(itemwrite);
 | 
					        OnWriteCompleted?.Invoke(itemwrite);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal OperResult AddOpcItem(OpcItem[] items)
 | 
					    internal List<Tuple<OpcItem, int>> AddOpcItem(OpcItem[] items)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IntPtr pResults = IntPtr.Zero;
 | 
					        IntPtr pResults = IntPtr.Zero;
 | 
				
			||||||
        IntPtr pErrors = IntPtr.Zero;
 | 
					        IntPtr pErrors = IntPtr.Zero;
 | 
				
			||||||
@@ -228,7 +225,7 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
            m_ItemManagement?.AddItems(items.Length, itemDefyArray, out pResults, out pErrors);
 | 
					            m_ItemManagement?.AddItems(items.Length, itemDefyArray, out pResults, out pErrors);
 | 
				
			||||||
            IntPtr Pos = pResults;
 | 
					            IntPtr Pos = pResults;
 | 
				
			||||||
            Marshal.Copy(pErrors, errors, 0, items.Length);
 | 
					            Marshal.Copy(pErrors, errors, 0, items.Length);
 | 
				
			||||||
            StringBuilder stringBuilder = new();
 | 
					            List<Tuple<OpcItem, int>> results = new();
 | 
				
			||||||
            for (int j = 0; j < items.Length; j++)
 | 
					            for (int j = 0; j < items.Length; j++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (errors[j] == 0)
 | 
					                if (errors[j] == 0)
 | 
				
			||||||
@@ -250,21 +247,10 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    stringBuilder.AppendLine(items[j].ItemID + "添加失败,错误代码:" + errors[j]);
 | 
					                    results.Add(Tuple.Create(items[j], errors[j]));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (stringBuilder.Length > 0)
 | 
					            return results;
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return new OperResult(stringBuilder.ToString());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return OperResult.CreateSuccessResult();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch (COMException ex)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return new OperResult(ex);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        finally
 | 
					        finally
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -299,7 +285,7 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
    /// 组读取
 | 
					    /// 组读取
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <exception cref="ExternalException"></exception>
 | 
					    /// <exception cref="ExternalException"></exception>
 | 
				
			||||||
    internal OperResult ReadAsync()
 | 
					    internal void ReadAsync()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IntPtr pErrors = IntPtr.Zero;
 | 
					        IntPtr pErrors = IntPtr.Zero;
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
@@ -316,16 +302,11 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
                Marshal.Copy(pErrors, PErrors, 0, OpcItems.Count);
 | 
					                Marshal.Copy(pErrors, PErrors, 0, OpcItems.Count);
 | 
				
			||||||
                if (PErrors.Any(a => a > 0))
 | 
					                if (PErrors.Any(a => a > 0))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return new OperResult("读取错误,错误代码:" + pErrors);
 | 
					                    throw new("读取错误,错误代码:" + pErrors);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return OperResult.CreateSuccessResult();
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                return new OperResult("连接无效");
 | 
					                throw new("连接无效");
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch (COMException ex)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return new OperResult(ex);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        finally
 | 
					        finally
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -336,7 +317,7 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal OperResult RemoveItem(OpcItem[] items)
 | 
					    internal List<Tuple<OpcItem, int>> RemoveItem(OpcItem[] items)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IntPtr pErrors = IntPtr.Zero;
 | 
					        IntPtr pErrors = IntPtr.Zero;
 | 
				
			||||||
        int[] errors = new int[items.Length];
 | 
					        int[] errors = new int[items.Length];
 | 
				
			||||||
@@ -356,59 +337,42 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                Marshal.FreeCoTaskMem(pErrors);
 | 
					                Marshal.FreeCoTaskMem(pErrors);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        StringBuilder stringBuilder = new();
 | 
					        List<Tuple<OpcItem, int>> results = new();
 | 
				
			||||||
        for (int i = 0; i < errors.Length; i++)
 | 
					        for (int i = 0; i < errors.Length; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (errors[i] != 0)
 | 
					            if (errors[i] != 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                stringBuilder.AppendLine(items[i].ItemID + "移除失败,错误代码:" + errors[i]);
 | 
					                results.Add(Tuple.Create(items[i], errors[i]));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                OpcItems.Remove(items[i]);
 | 
					                OpcItems.Remove(items[i]);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (stringBuilder.Length > 0)
 | 
					        return results;
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return new OperResult(stringBuilder.ToString());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return OperResult.CreateSuccessResult();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    internal OperResult Write(object[] values, int[] serverHandle, out int[] errors)
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal List<Tuple<int, int>> Write(object[] values, int[] serverHandle)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IntPtr pErrors = IntPtr.Zero;
 | 
					        IntPtr pErrors = IntPtr.Zero;
 | 
				
			||||||
        errors = new int[values.Length];
 | 
					        var errors = new int[values.Length];
 | 
				
			||||||
        if (m_Async2IO != null)
 | 
					        if (m_Async2IO != null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                m_SyncIO.Write(values.Length, serverHandle, values, out pErrors);
 | 
					                m_SyncIO.Write(values.Length, serverHandle, values, out pErrors);
 | 
				
			||||||
                Marshal.Copy(pErrors, errors, 0, values.Length);
 | 
					                Marshal.Copy(pErrors, errors, 0, values.Length);
 | 
				
			||||||
                StringBuilder stringBuilder = new();
 | 
					                List<Tuple<int, int>> results = new();
 | 
				
			||||||
                for (int i = 0; i < errors.Length; i++)
 | 
					                for (int i = 0; i < errors.Length; i++)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    if (errors[i] != 0)
 | 
					                    if (errors[i] != 0)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        stringBuilder.AppendLine("写入错误,错误代码:" + errors[i]);
 | 
					                        results.Add(Tuple.Create(serverHandle[i], errors[i]));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (stringBuilder.Length > 0)
 | 
					                return results;
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    return new(stringBuilder.ToString());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    return OperResult.CreateSuccessResult();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch (COMException ex)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return new OperResult(ex);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            finally
 | 
					            finally
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -419,7 +383,7 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            return new OperResult("连接无效");
 | 
					            throw new("连接无效");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    protected virtual void Dispose(bool disposing)
 | 
					    protected virtual void Dispose(bool disposing)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -465,7 +429,7 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private OperResult ActiveDataChanged(bool active)
 | 
					    private void ActiveDataChanged(bool active)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IntPtr pRequestedUpdateRate = IntPtr.Zero;
 | 
					        IntPtr pRequestedUpdateRate = IntPtr.Zero;
 | 
				
			||||||
        IntPtr hClientGroup = IntPtr.Zero;
 | 
					        IntPtr hClientGroup = IntPtr.Zero;
 | 
				
			||||||
@@ -484,11 +448,6 @@ internal class OpcGroup : IOPCDataCallback, IDisposable
 | 
				
			|||||||
                                        pDeadband,
 | 
					                                        pDeadband,
 | 
				
			||||||
                                        pLCID,
 | 
					                                        pLCID,
 | 
				
			||||||
                                        hClientGroup);
 | 
					                                        hClientGroup);
 | 
				
			||||||
            return OperResult.CreateSuccessResult();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch (COMException ex)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return new OperResult(ex);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        finally
 | 
					        finally
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -10,8 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Runtime.InteropServices;
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
					using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
				
			||||||
@@ -51,58 +49,51 @@ internal class OpcServer : IDisposable
 | 
				
			|||||||
        GC.SuppressFinalize(this);
 | 
					        GC.SuppressFinalize(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal OperResult<OpcGroup> AddGroup(string groupName)
 | 
					    internal OpcGroup AddGroup(string groupName)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return AddGroup(groupName, true, 1000, 0);
 | 
					        return AddGroup(groupName, true, 1000, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    internal OperResult<OpcGroup> AddGroup(string groupName, bool active, int reqUpdateRate, float deadBand)
 | 
					    internal OpcGroup AddGroup(string groupName, bool active, int reqUpdateRate, float deadBand)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (null == m_OpcServer || IsConnected == false)
 | 
					        if (null == m_OpcServer || IsConnected == false)
 | 
				
			||||||
            return new OperResult<OpcGroup>("未初始化连接!");
 | 
					            throw new("未初始化连接!");
 | 
				
			||||||
        OpcGroup group = new(groupName, active, reqUpdateRate, deadBand);
 | 
					        OpcGroup group = new(groupName, active, reqUpdateRate, deadBand);
 | 
				
			||||||
        Guid riid = typeof(IOPCItemMgt).GUID;
 | 
					        Guid riid = typeof(IOPCItemMgt).GUID;
 | 
				
			||||||
        try
 | 
					        m_OpcServer?.AddGroup(group.Name,
 | 
				
			||||||
 | 
					            group.IsActive ? 1 : 0,//IsActive
 | 
				
			||||||
 | 
					            group.RequestUpdateRate,//RequestedUpdateRate 1000ms
 | 
				
			||||||
 | 
					            group.ClientGroupHandle,
 | 
				
			||||||
 | 
					            group.TimeBias.AddrOfPinnedObject(),
 | 
				
			||||||
 | 
					            group.PercendDeadBand.AddrOfPinnedObject(),
 | 
				
			||||||
 | 
					            group.LCID,
 | 
				
			||||||
 | 
					            out group.serverGroupHandle,
 | 
				
			||||||
 | 
					            out group.revisedUpdateRate,
 | 
				
			||||||
 | 
					            ref riid,
 | 
				
			||||||
 | 
					            out group.groupPointer);
 | 
				
			||||||
 | 
					        if (group.groupPointer != null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            m_OpcServer?.AddGroup(group.Name,
 | 
					            group.InitIoInterfaces(group.groupPointer);
 | 
				
			||||||
                group.IsActive ? 1 : 0,//IsActive
 | 
					            OpcGroups.Add(group);
 | 
				
			||||||
                group.RequestUpdateRate,//RequestedUpdateRate 1000ms
 | 
					 | 
				
			||||||
                group.ClientGroupHandle,
 | 
					 | 
				
			||||||
                group.TimeBias.AddrOfPinnedObject(),
 | 
					 | 
				
			||||||
                group.PercendDeadBand.AddrOfPinnedObject(),
 | 
					 | 
				
			||||||
                group.LCID,
 | 
					 | 
				
			||||||
                out group.serverGroupHandle,
 | 
					 | 
				
			||||||
                out group.revisedUpdateRate,
 | 
					 | 
				
			||||||
                ref riid,
 | 
					 | 
				
			||||||
                out group.groupPointer);
 | 
					 | 
				
			||||||
            if (group.groupPointer != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                group.InitIoInterfaces(group.groupPointer);
 | 
					 | 
				
			||||||
                OpcGroups.Add(group);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return new OperResult<OpcGroup>("添加OPC组错误,OPC服务器返回null");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return OperResult.CreateSuccessResult(group);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new OperResult<OpcGroup>(ex);
 | 
					            throw new("添加OPC组错误,OPC服务器返回null");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 获取节点
 | 
					    /// 获取节点
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    internal OperResult<List<BrowseElement>> Browse(string itemId = null)
 | 
					    internal List<BrowseElement> Browse(string itemId = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        lock (this)
 | 
					        lock (this)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (null == m_OpcServer || IsConnected == false)
 | 
					            if (null == m_OpcServer || IsConnected == false)
 | 
				
			||||||
                return new OperResult<List<BrowseElement>>("未初始化连接!");
 | 
					                throw new("未初始化连接!");
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var count = 0;
 | 
					            var count = 0;
 | 
				
			||||||
            var moreElements = 0;
 | 
					            var moreElements = 0;
 | 
				
			||||||
@@ -118,108 +109,107 @@ internal class OpcServer : IDisposable
 | 
				
			|||||||
                           new PropertyID(6),
 | 
					                           new PropertyID(6),
 | 
				
			||||||
                           new PropertyID(101),
 | 
					                           new PropertyID(101),
 | 
				
			||||||
                         };
 | 
					                         };
 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var server = m_OpcServer as IOPCBrowse;
 | 
					
 | 
				
			||||||
                server.Browse(
 | 
					            var server = m_OpcServer as IOPCBrowse;
 | 
				
			||||||
                         string.IsNullOrEmpty(itemId) ? "" : itemId,
 | 
					            server.Browse(
 | 
				
			||||||
                     ref pContinuationPoint,
 | 
					                     string.IsNullOrEmpty(itemId) ? "" : itemId,
 | 
				
			||||||
                     int.MaxValue,
 | 
					                 ref pContinuationPoint,
 | 
				
			||||||
                        OPCBROWSEFILTER.OPC_BROWSE_FILTER_ALL,
 | 
					                 int.MaxValue,
 | 
				
			||||||
                          "",
 | 
					                    OPCBROWSEFILTER.OPC_BROWSE_FILTER_ALL,
 | 
				
			||||||
                         "",
 | 
					                      "",
 | 
				
			||||||
                         0,
 | 
					                     "",
 | 
				
			||||||
                         1,
 | 
					                     0,
 | 
				
			||||||
                         filterId.Length,
 | 
					                     1,
 | 
				
			||||||
                         Interop.GetPropertyIDs(filterId),
 | 
					                     filterId.Length,
 | 
				
			||||||
                     out moreElements,
 | 
					                     Interop.GetPropertyIDs(filterId),
 | 
				
			||||||
                     out count,
 | 
					                 out moreElements,
 | 
				
			||||||
                     out pElements);
 | 
					                 out count,
 | 
				
			||||||
            }
 | 
					                 out pElements);
 | 
				
			||||||
            catch (Exception ex)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return new OperResult<List<BrowseElement>>(ex);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            BrowseElement[] browseElements = Interop.GetBrowseElements(ref pElements, count, true);
 | 
					            BrowseElement[] browseElements = Interop.GetBrowseElements(ref pElements, count, true);
 | 
				
			||||||
            string stringUni = Marshal.PtrToStringUni(pContinuationPoint);
 | 
					            string stringUni = Marshal.PtrToStringUni(pContinuationPoint);
 | 
				
			||||||
            Marshal.FreeCoTaskMem(pContinuationPoint);
 | 
					            Marshal.FreeCoTaskMem(pContinuationPoint);
 | 
				
			||||||
            this.ProcessResults(browseElements, filterId);
 | 
					            this.ProcessResults(browseElements, filterId);
 | 
				
			||||||
            return OperResult.CreateSuccessResult(browseElements?.ToList());
 | 
					            return browseElements?.ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal OperResult Connect()
 | 
					    internal void Connect()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (!string.IsNullOrEmpty(Host) && !string.IsNullOrEmpty(Name))
 | 
					        if (!string.IsNullOrEmpty(Host) && !string.IsNullOrEmpty(Name))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var info = Discovery.OpcDiscovery.GetOpcServer(Name, Host);
 | 
					            var info = Discovery.OpcDiscovery.GetOpcServer(Name, Host);
 | 
				
			||||||
            if (!info.IsSuccess)
 | 
					            object o = Comn.ComInterop.CreateInstance(info.CLSID, Host);
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return info;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            object o = Comn.ComInterop.CreateInstance(info.Content.CLSID, Host);
 | 
					 | 
				
			||||||
            if (o == null)
 | 
					            if (o == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return new(string.Format("{0}{1}无法创建com对象", info.Content.CLSID, Host));
 | 
					                throw new(string.Format("{0}{1}无法创建com对象", info.CLSID, Host));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            m_OpcServer = (IOPCServer)o;
 | 
					            m_OpcServer = (IOPCServer)o;
 | 
				
			||||||
            IsConnected = true;
 | 
					            IsConnected = true;
 | 
				
			||||||
            return OperResult.CreateSuccessResult();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return new("应初始化Host与Name");
 | 
					        else
 | 
				
			||||||
 | 
					            throw new("应初始化Host与Name");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 服务器状态
 | 
					    /// 服务器状态
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    internal OperResult<ServerStatus> GetServerStatus()
 | 
					    internal ServerStatus GetServerStatus()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (null == m_OpcServer || IsConnected == false)
 | 
					        ServerStatus serverStatus = null;
 | 
				
			||||||
            return new OperResult<ServerStatus>("未初始化连接!");
 | 
					 | 
				
			||||||
        IntPtr statusPtr = IntPtr.Zero;
 | 
					 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (null == m_OpcServer || IsConnected == false)
 | 
				
			||||||
 | 
					                throw new("未初始化连接!");
 | 
				
			||||||
 | 
					            IntPtr statusPtr = IntPtr.Zero;
 | 
				
			||||||
            m_OpcServer?.GetStatus(out statusPtr);
 | 
					            m_OpcServer?.GetStatus(out statusPtr);
 | 
				
			||||||
            OPCSERVERSTATUS status;
 | 
					            OPCSERVERSTATUS status;
 | 
				
			||||||
            ServerStatus = new ServerStatus();
 | 
					 | 
				
			||||||
            if (statusPtr != IntPtr.Zero)
 | 
					            if (statusPtr != IntPtr.Zero)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                try
 | 
					
 | 
				
			||||||
 | 
					                object o = Marshal.PtrToStructure(statusPtr, typeof(OPCSERVERSTATUS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Marshal.FreeCoTaskMem(statusPtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (o != null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    object o = Marshal.PtrToStructure(statusPtr, typeof(OPCSERVERSTATUS));
 | 
					                    status = (OPCSERVERSTATUS)o;
 | 
				
			||||||
                    if (null != o)
 | 
					                    serverStatus = new();
 | 
				
			||||||
                    {
 | 
					                    serverStatus.Version = status.wMajorVersion.ToString() + "." + status.wMinorVersion.ToString() + "." + status.wBuildNumber.ToString();
 | 
				
			||||||
                        status = (OPCSERVERSTATUS)o;
 | 
					                    serverStatus.ServerState = status.dwServerState;
 | 
				
			||||||
                        ServerStatus.Version = status.wMajorVersion.ToString() + "." + status.wMinorVersion.ToString() + "." + status.wBuildNumber.ToString();
 | 
					                    serverStatus.StartTime = Comn.Convert.FileTimeToDateTime(status.ftStartTime);
 | 
				
			||||||
                        ServerStatus.ServerState = status.dwServerState;
 | 
					                    serverStatus.CurrentTime = Comn.Convert.FileTimeToDateTime(status.ftCurrentTime);
 | 
				
			||||||
                        ServerStatus.StartTime = Comn.Convert.FileTimeToDateTime(status.ftStartTime);
 | 
					                    serverStatus.LastUpdateTime = Comn.Convert.FileTimeToDateTime(status.ftLastUpdateTime);
 | 
				
			||||||
                        ServerStatus.CurrentTime = Comn.Convert.FileTimeToDateTime(status.ftCurrentTime);
 | 
					                    serverStatus.VendorInfo = status.szVendorInfo;
 | 
				
			||||||
                        ServerStatus.LastUpdateTime = Comn.Convert.FileTimeToDateTime(status.ftLastUpdateTime);
 | 
					 | 
				
			||||||
                        ServerStatus.VendorInfo = status.szVendorInfo;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    IsConnected = true;
 | 
					                    IsConnected = true;
 | 
				
			||||||
                    return OperResult.CreateSuccessResult(ServerStatus);
 | 
					
 | 
				
			||||||
 | 
					                    return serverStatus;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (Exception ex)
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    IsConnected = false;
 | 
					                    IsConnected = false;
 | 
				
			||||||
                    return new OperResult<ServerStatus>(ex);
 | 
					                    throw new("未知错误");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                IsConnected = false;
 | 
					                IsConnected = false;
 | 
				
			||||||
                return new OperResult<ServerStatus>("获取状态失败");
 | 
					                throw new("未知错误");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        finally
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IsConnected = false;
 | 
					            if (serverStatus != null)
 | 
				
			||||||
            return new OperResult<ServerStatus>(ex);
 | 
					                IsConnected = true;
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                IsConnected = false;
 | 
				
			||||||
 | 
					            ServerStatus = serverStatus;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal void RemoveGroup(OpcGroup group)
 | 
					    internal void RemoveGroup(OpcGroup group)
 | 
				
			||||||
@@ -10,15 +10,11 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Newtonsoft.Json.Linq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using System.Collections;
 | 
					using System.Collections;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
					using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using TouchSocket.Core;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.OPCDA.Discovery;
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCDA.Discovery;
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// OpcDiscovery
 | 
					/// OpcDiscovery
 | 
				
			||||||
@@ -38,58 +34,58 @@ public class OpcDiscovery
 | 
				
			|||||||
    /// <param name="serverName"></param>
 | 
					    /// <param name="serverName"></param>
 | 
				
			||||||
    /// <param name="host"></param>
 | 
					    /// <param name="host"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    internal static OperResult<ServerInfo> GetOpcServer(string serverName, string host)
 | 
					    internal static ServerInfo GetOpcServer(string serverName, string host)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (string.IsNullOrEmpty(serverName))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new("检索失败,需提供OPCName");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ServerInfo result = null;
 | 
				
			||||||
 | 
					        ServerInfo[] serverInfos = null;
 | 
				
			||||||
 | 
					        object o_Server = Comn.ComInterop.CreateInstance(OPCEnumCLSID, host);
 | 
				
			||||||
 | 
					        if (o_Server == null)
 | 
				
			||||||
 | 
					            throw new("检索失败,请检查是否安装OPC Runtime");
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(serverName))
 | 
					            Guid catid = CATID_OPC_DA20;
 | 
				
			||||||
            {
 | 
					
 | 
				
			||||||
                return new OperResult<ServerInfo>("检索失败,需提供OPCName");
 | 
					            //两种方式,兼容国产部分OPCServer不支持IOPCServerList2的情况
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ServerInfo result = null;
 | 
					 | 
				
			||||||
            ServerInfo[] serverInfos = null;
 | 
					 | 
				
			||||||
            object o_Server = Comn.ComInterop.CreateInstance(OPCEnumCLSID, host);
 | 
					 | 
				
			||||||
            if (o_Server == null)
 | 
					 | 
				
			||||||
                return new OperResult<ServerInfo>("检索失败,请检查是否安装OPC Runtime");
 | 
					 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Guid catid = CATID_OPC_DA20;
 | 
					                IOPCServerList2 m_server2 = (IOPCServerList2)o_Server;
 | 
				
			||||||
 | 
					                GetIOPCServerList(ref result, ref serverInfos, serverName, host, m_server2, catid);
 | 
				
			||||||
                //两种方式,兼容国产部分OPCServer不支持IOPCServerList2的情况
 | 
					                if (result == null)
 | 
				
			||||||
                try
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    IOPCServerList2 m_server2 = (IOPCServerList2)o_Server;
 | 
					 | 
				
			||||||
                    GetIOPCServerList(ref result, ref serverInfos, serverName, host, m_server2, catid);
 | 
					 | 
				
			||||||
                    if (result == null)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        IOPCServerList m_server = (IOPCServerList)o_Server;
 | 
					 | 
				
			||||||
                        GetIOPCServerList(ref result, ref serverInfos, serverName, host, m_server, catid);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                catch (Exception)
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    IOPCServerList m_server = (IOPCServerList)o_Server;
 | 
					                    IOPCServerList m_server = (IOPCServerList)o_Server;
 | 
				
			||||||
                    GetIOPCServerList(ref result, ref serverInfos, serverName, host, m_server, catid);
 | 
					                    GetIOPCServerList(ref result, ref serverInfos, serverName, host, m_server, catid);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (result == null)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    return new OperResult<ServerInfo>($"无法创建OPCServer连接,请检查OPC名称是否一致,以下为Host{host}中的OPC列表:"
 | 
					 | 
				
			||||||
                        + Environment.NewLine +
 | 
					 | 
				
			||||||
                      JToken.Parse(serverInfos.ToJsonString()).ToString()
 | 
					 | 
				
			||||||
                        );
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return OperResult.CreateSuccessResult(result);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            finally
 | 
					            catch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Comn.ComInterop.RealseComServer(o_Server);
 | 
					                IOPCServerList m_server = (IOPCServerList)o_Server;
 | 
				
			||||||
                o_Server = null;
 | 
					                GetIOPCServerList(ref result, ref serverInfos, serverName, host, m_server, catid);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (result == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                StringBuilder sb = new StringBuilder();
 | 
				
			||||||
 | 
					                foreach (var item in serverInfos)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sb.AppendLine(item.ToString());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                throw new($"无法创建OPCServer连接,请检查OPC名称是否一致,以下为{host}中的OPC列表:"
 | 
				
			||||||
 | 
					                    + Environment.NewLine +
 | 
				
			||||||
 | 
					                  sb.ToString()
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        finally
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new OperResult<ServerInfo>(ex);
 | 
					            Comn.ComInterop.RealseComServer(o_Server);
 | 
				
			||||||
 | 
					            o_Server = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static void GetIOPCServerList(ref ServerInfo result, ref ServerInfo[] serverInfos, string serverName, string host, IOPCServerList m_server, Guid catid)
 | 
					    private static void GetIOPCServerList(ref ServerInfo result, ref ServerInfo[] serverInfos, string serverName, string host, IOPCServerList m_server, Guid catid)
 | 
				
			||||||
@@ -246,4 +242,15 @@ internal class ServerInfo
 | 
				
			|||||||
    internal string Host { get; set; } = string.Empty;
 | 
					    internal string Host { get; set; } = string.Empty;
 | 
				
			||||||
    internal string ProgID { get; set; } = string.Empty;
 | 
					    internal string ProgID { get; set; } = string.Empty;
 | 
				
			||||||
    internal string VerIndProgID { get; set; } = string.Empty;
 | 
					    internal string VerIndProgID { get; set; } = string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override string ToString()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StringBuilder stringBuilder = new StringBuilder();
 | 
				
			||||||
 | 
					        stringBuilder.AppendLine($"{nameof(CLSID)}:{CLSID}");
 | 
				
			||||||
 | 
					        stringBuilder.AppendLine($"{nameof(Description)}:{Description}");
 | 
				
			||||||
 | 
					        stringBuilder.AppendLine($"{nameof(Host)}:{Host}");
 | 
				
			||||||
 | 
					        stringBuilder.AppendLine($"{nameof(ProgID)}:{ProgID}");
 | 
				
			||||||
 | 
					        stringBuilder.AppendLine($"{nameof(VerIndProgID)}:{VerIndProgID}");
 | 
				
			||||||
 | 
					        return stringBuilder.ToString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -10,9 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.OPCDA;
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCDA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal static class CollectionExtensions
 | 
					internal static class CollectionExtensions
 | 
				
			||||||
@@ -23,11 +20,30 @@ internal static class CollectionExtensions
 | 
				
			|||||||
    /// <typeparam name="T"></typeparam>
 | 
					    /// <typeparam name="T"></typeparam>
 | 
				
			||||||
    /// <param name="this"></param>
 | 
					    /// <param name="this"></param>
 | 
				
			||||||
    /// <param name="where"></param>
 | 
					    /// <param name="where"></param>
 | 
				
			||||||
    public static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
 | 
					    internal static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        foreach (var obj in @this.Where(where).ToList())
 | 
					        foreach (var obj in @this.Where(where).ToList())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            @this.Remove(obj);
 | 
					            @this.Remove(obj);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 将项目列表分解为特定大小的块
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="T"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="source"></param>
 | 
				
			||||||
 | 
					    /// <param name="chunksize"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static List<List<T>> ChunkTrivialBetter<T>(this IEnumerable<T> source, int chunksize)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var pos = 0;
 | 
				
			||||||
 | 
					        List<List<T>> n = new();
 | 
				
			||||||
 | 
					        while (source.Skip(pos).Any())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            n.Add(source.Skip(pos).Take(chunksize).ToList());
 | 
				
			||||||
 | 
					            pos += chunksize;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return n;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
 | 
				
			||||||
 | 
					//  CSDN博客:https://blog.csdn.net/qq_40374647
 | 
				
			||||||
 | 
					//  哔哩哔哩视频:https://space.bilibili.com/94253567
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/RRQM_Home
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/RRQM
 | 
				
			||||||
 | 
					//  API首页:http://rrqm_home.gitee.io/touchsocket/
 | 
				
			||||||
 | 
					//  交流QQ群:234762506
 | 
				
			||||||
 | 
					//  感谢您的下载和使用
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCDA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// DictionaryExtension
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					internal static class DictionaryExtension
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    #region 字典扩展
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 移除满足条件的项目。
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="TKey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="pairs"></param>
 | 
				
			||||||
 | 
					    /// <param name="func"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static int RemoveWhen<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> pairs, Func<KeyValuePair<TKey, TValue>, bool> func)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var list = new List<TKey>();
 | 
				
			||||||
 | 
					        foreach (var item in pairs)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (func?.Invoke(item) == true)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                list.Add(item.Key);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var count = 0;
 | 
				
			||||||
 | 
					        foreach (var item in list)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (pairs.TryRemove(item, out _))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                count++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return count;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if NET45_OR_GREATER || NETSTANDARD2_0_OR_GREATER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 尝试添加
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="Tkey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="dictionary"></param>
 | 
				
			||||||
 | 
					    /// <param name="tkey"></param>
 | 
				
			||||||
 | 
					    /// <param name="value"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static bool TryAdd<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (dictionary.ContainsKey(tkey))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dictionary.Add(tkey, value);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 尝试添加
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="Tkey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="dictionary"></param>
 | 
				
			||||||
 | 
					    /// <param name="tkey"></param>
 | 
				
			||||||
 | 
					    /// <param name="value"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static void AddOrUpdate<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (dictionary.ContainsKey(tkey))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            dictionary[tkey] = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            dictionary.Add(tkey, value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 获取值。如果键不存在,则返回默认值。
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="Tkey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="dictionary"></param>
 | 
				
			||||||
 | 
					    /// <param name="tkey"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static TValue GetValue<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return dictionary.TryGetValue(tkey, out var value) ? value : default;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #endregion 字典扩展
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -13,5 +13,5 @@
 | 
				
			|||||||
global using System;
 | 
					global using System;
 | 
				
			||||||
global using System.Collections.Generic;
 | 
					global using System.Collections.Generic;
 | 
				
			||||||
global using System.Linq;
 | 
					global using System.Linq;
 | 
				
			||||||
global using System.Threading.Tasks;
 | 
					global using System.Threading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,457 @@
 | 
				
			|||||||
 | 
					#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.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Timers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Adapter.OPCDA.Da;
 | 
				
			||||||
 | 
					using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Timer = System.Timers.Timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//部分非托管交互代码来自https://gitee.com/Zer0Day/opc-client与OPC基金会opcnet库,更改部分逻辑
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCDA;
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// 订阅变化项
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <param name="values"></param>
 | 
				
			||||||
 | 
					public delegate void DataChangedEventHandler(List<ItemReadResult> values);
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// OPCDAClient
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class OPCDAClient : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// LogAction
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private readonly Action<byte, object, string, Exception> _logAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private readonly object checkLock = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Timer checkTimer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private int IsExit = 1;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 当前保存的需订阅列表
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    private Dictionary<string, List<OpcItem>> ItemDicts = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OpcServer m_server;
 | 
				
			||||||
 | 
					    private bool publicConnect;
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public OPCDAClient(Action<byte, object, string, Exception> logAction)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if (NET6_0_OR_GREATER)
 | 
				
			||||||
 | 
					        if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new NotSupportedException("不支持非windows系统");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        _logAction = logAction;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 数据变化事件
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public event DataChangedEventHandler DataChangedHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否连接成功
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool IsConnected => m_server?.IsConnected == true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 当前配置
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public OPCNode OPCNode { get; private set; }
 | 
				
			||||||
 | 
					    private List<OpcGroup> Groups => m_server.OpcGroups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 添加节点,需要在连接成功后执行
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="items">组名称/变量节点,注意每次添加的组名称不能相同</param>
 | 
				
			||||||
 | 
					    public void AddItems(Dictionary<string, List<OpcItem>> items)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (IsExit == 1) throw new("对象已释放");
 | 
				
			||||||
 | 
					        foreach (var item in items)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (IsExit == 1) throw new("对象已释放");
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var subscription = m_server.AddGroup(item.Key, true, OPCNode.UpdateRate, OPCNode.DeadBand);
 | 
				
			||||||
 | 
					                subscription.ActiveSubscribe = OPCNode.ActiveSubscribe;
 | 
				
			||||||
 | 
					                subscription.OnDataChanged += Subscription_OnDataChanged;
 | 
				
			||||||
 | 
					                subscription.OnReadCompleted += Subscription_OnDataChanged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var result = subscription.AddOpcItem(item.Value.ToArray());
 | 
				
			||||||
 | 
					                StringBuilder stringBuilder = new StringBuilder();
 | 
				
			||||||
 | 
					                if (result.Count > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var item1 in result)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        stringBuilder.Append($"{item1.Item1.ItemID}:{item1.Item2}");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    _logAction?.Invoke(3, this, $"添加变量失败:{stringBuilder}", null);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ItemDicts.AddOrUpdate(item.Key, item.Value.Where(a => !result.Select(b => b.Item1).Contains(a)).ToList());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _logAction?.Invoke(3, this, $"添加组失败:{ex.Message}", ex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (int i = 0; i < Groups?.Count; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var group = Groups[i];
 | 
				
			||||||
 | 
					            if (group != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (group.OpcItems.Count == 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ItemDicts.Remove(group.Name);
 | 
				
			||||||
 | 
					                    m_server.RemoveGroup(group);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 设置节点并保存,每次重连会自动添加节点
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="items"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public Dictionary<string, List<OpcItem>> AddItemsWithSave(List<string> items)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int i = 0;
 | 
				
			||||||
 | 
					        ItemDicts = items.ToList().ConvertAll(o => new OpcItem(o)).ChunkTrivialBetter(OPCNode.GroupSize).ToDictionary(a => "default" + (i++));
 | 
				
			||||||
 | 
					        return ItemDicts;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 连接服务器
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Connect()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        publicConnect = true;
 | 
				
			||||||
 | 
					        Interlocked.CompareExchange(ref IsExit, 0, 1);
 | 
				
			||||||
 | 
					        PrivateConnect();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 断开连接
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Disconnect()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Interlocked.CompareExchange(ref IsExit, 1, 0);
 | 
				
			||||||
 | 
					        PrivateDisconnect();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            PrivateDisconnect();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logAction?.Invoke(3, this, $"连接释放失败:{ex.Message}", ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Interlocked.CompareExchange(ref IsExit, 1, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 浏览节点
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="itemId"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public List<BrowseElement> GetBrowseElements(string itemId = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return this.m_server?.Browse(itemId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 获取服务状态
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public ServerStatus GetServerStatus()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return this.m_server?.GetServerStatus();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 初始化设置
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="node"></param>
 | 
				
			||||||
 | 
					    public void Init(OPCNode node)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (node != null)
 | 
				
			||||||
 | 
					            OPCNode = node;
 | 
				
			||||||
 | 
					        checkTimer?.Stop();
 | 
				
			||||||
 | 
					        checkTimer?.Dispose();
 | 
				
			||||||
 | 
					        checkTimer = new Timer(OPCNode.CheckRate * 60 * 1000);
 | 
				
			||||||
 | 
					        checkTimer.Elapsed += CheckTimer_Elapsed;
 | 
				
			||||||
 | 
					        checkTimer.Start();
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            m_server?.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logAction?.Invoke(3, this, $"连接释放失败:{ex.Message}", ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        m_server = new OpcServer(OPCNode.OPCName, OPCNode.OPCIP);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 按OPC组读取组内变量,结果会在订阅事件中返回
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="groupName">组名称,值为null时读取全部组</param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public void ReadItemsWithGroup(string groupName = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        PrivateConnect();
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var groups = groupName != null ? Groups.Where(a => a.Name == groupName) : Groups;
 | 
				
			||||||
 | 
					            foreach (var group in groups)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (group.OpcItems.Count > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    group.ReadAsync();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 移除节点
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="items"></param>
 | 
				
			||||||
 | 
					    public void RemoveItems(List<string> items)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach (var item in items)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (IsExit == 1) return;
 | 
				
			||||||
 | 
					            var opcGroups = Groups.Where(it => it.OpcItems.Any(a => a.ItemID == item));
 | 
				
			||||||
 | 
					            foreach (var opcGroup in opcGroups)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var tag = opcGroup.OpcItems.Where(a => item == a.ItemID);
 | 
				
			||||||
 | 
					                var result = opcGroup.RemoveItem(tag.ToArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (opcGroup.OpcItems.Count == 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    opcGroup.OnDataChanged -= Subscription_OnDataChanged;
 | 
				
			||||||
 | 
					                    ItemDicts.Remove(opcGroup.Name);
 | 
				
			||||||
 | 
					                    m_server.RemoveGroup(opcGroup);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ItemDicts[opcGroup.Name].RemoveWhere(a => tag.Contains(a) && !result.Select(b => b.Item1).Contains(a));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
 | 
					    public override string ToString()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return OPCNode?.ToString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 批量写入值
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public Dictionary<string, Tuple<bool, string>> WriteItem(Dictionary<string, object> writeInfos)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        PrivateConnect();
 | 
				
			||||||
 | 
					        Dictionary<string, Tuple<bool, string>> results = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var valueGroup = writeInfos.GroupBy(itemId =>
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					              var group = Groups.FirstOrDefault(it => it.OpcItems.Any(a => a.ItemID == itemId.Key));
 | 
				
			||||||
 | 
					              return group;
 | 
				
			||||||
 | 
					          }).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var item1 in valueGroup)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (item1.Key == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var item2 in item1)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        results.AddOrUpdate(item2.Key, Tuple.Create(true, $"不存在该变量{item2.Key}"));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    List<int> serverHandles = new();
 | 
				
			||||||
 | 
					                    Dictionary<int, OpcItem> handleItems = new();
 | 
				
			||||||
 | 
					                    List<object> values = new();
 | 
				
			||||||
 | 
					                    foreach (var item2 in item1)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var opcItem = item1.Key.OpcItems.Where(it => it.ItemID == item2.Key).FirstOrDefault();
 | 
				
			||||||
 | 
					                        serverHandles.Add(opcItem.ServerHandle);
 | 
				
			||||||
 | 
					                        handleItems.AddOrUpdate(opcItem.ServerHandle, opcItem);
 | 
				
			||||||
 | 
					                        var rawWriteValue = item2.Value;
 | 
				
			||||||
 | 
					                        values.Add(rawWriteValue);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var result = item1.Key.Write(values.ToArray(), serverHandles.ToArray());
 | 
				
			||||||
 | 
					                    var data = item1.ToList();
 | 
				
			||||||
 | 
					                    foreach (var item2 in result)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        results.AddOrUpdate(handleItems[item2.Item1].ItemID, Tuple.Create(true, $"错误代码{item2.Item2}"));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                foreach (var item2 in item1)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    results.AddOrUpdate(item2.Key, Tuple.Create(false, $"成功"));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var keys = writeInfos.Keys.ToList();
 | 
				
			||||||
 | 
					                foreach (var item in keys)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    results.AddOrUpdate(item, Tuple.Create(true, ex.Message));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return results;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return results;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private void CheckTimer_Elapsed(object sender, ElapsedEventArgs e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lock (checkLock)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (IsExit == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var status = m_server.GetServerStatus();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (IsExit == 0 && publicConnect)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        try
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            PrivateConnect();
 | 
				
			||||||
 | 
					                            _logAction?.Invoke(1, this, $"重新链接成功", null);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        catch (Exception ex)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            _logAction?.Invoke(3, this, $"重新链接失败:{ex.Message}", ex);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var timeer = sender as Timer;
 | 
				
			||||||
 | 
					                timeer.Enabled = false;
 | 
				
			||||||
 | 
					                timeer.Stop();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void PrivateAddItems()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            AddItems(ItemDicts);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logAction?.Invoke(3, this, $"添加点位失败:{ex.Message}", ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private void PrivateConnect()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lock (this)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (m_server?.IsConnected == true)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var status = m_server.GetServerStatus();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var status1 = m_server.GetServerStatus();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        Init(OPCNode);
 | 
				
			||||||
 | 
					                        m_server?.Connect();
 | 
				
			||||||
 | 
					                        _logAction?.Invoke(1, this, $"{m_server.Host} - {m_server.Name} - 连接成功", null);
 | 
				
			||||||
 | 
					                        PrivateAddItems();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Init(OPCNode);
 | 
				
			||||||
 | 
					                m_server?.Connect();
 | 
				
			||||||
 | 
					                _logAction?.Invoke(1, this, $"{m_server.Host} - {m_server.Name} - 连接成功", null);
 | 
				
			||||||
 | 
					                PrivateAddItems();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void PrivateDisconnect()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lock (this)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (IsConnected)
 | 
				
			||||||
 | 
					                _logAction?.Invoke(1, this, $"{m_server.Host} - {m_server.Name} - 断开连接", null);
 | 
				
			||||||
 | 
					            if (checkTimer != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                checkTimer.Enabled = false;
 | 
				
			||||||
 | 
					                checkTimer.Stop();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                m_server?.Dispose();
 | 
				
			||||||
 | 
					                m_server = null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _logAction?.Invoke(3, this, $"连接释放失败:{ex.Message}", ex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private void Subscription_OnDataChanged(List<ItemReadResult> values)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DataChangedHandler?.Invoke(values);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -21,7 +21,7 @@ public class OPCNode
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 是否订阅
 | 
					    /// 是否订阅
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [Description("ActiveSubscribe")]
 | 
					    [Description("订阅")]
 | 
				
			||||||
    public bool ActiveSubscribe { get; set; } = true;
 | 
					    public bool ActiveSubscribe { get; set; } = true;
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 内部检测重连间隔/min
 | 
					    /// 内部检测重连间隔/min
 | 
				
			||||||
@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -441,7 +441,7 @@
 | 
				
			|||||||
            当前保存的需订阅列表
 | 
					            当前保存的需订阅列表
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.#ctor(TouchSocket.Core.ILog)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.#ctor(ThingsGateway.Foundation.ILog)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            <inheritdoc/>
 | 
					            <inheritdoc/>
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
@@ -39,7 +39,7 @@ public class OPCNode
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    [Description("检查域")]
 | 
					    [Description("检查域")]
 | 
				
			||||||
    public bool CheckDomain { get; set; }
 | 
					    public bool CheckDomain { get; set; }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 更新间隔
 | 
					    /// 更新间隔
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -17,13 +17,6 @@ using Opc.Ua.Client;
 | 
				
			|||||||
using Opc.Ua.Client.ComplexTypes;
 | 
					using Opc.Ua.Client.ComplexTypes;
 | 
				
			||||||
using Opc.Ua.Configuration;
 | 
					using Opc.Ua.Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using ThingsGateway.Foundation.Extension;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
//修改自https://github.com/dathlin/OpcUaHelper 与OPC基金会net库
 | 
					//修改自https://github.com/dathlin/OpcUaHelper 与OPC基金会net库
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +29,7 @@ public delegate void DataChangedEventHandler((VariableNode variableNode, DataVal
 | 
				
			|||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// OPCUAClient
 | 
					/// OPCUAClient
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
public class OPCUAClient : DisposableObject
 | 
					public class OPCUAClient : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region 属性,变量等
 | 
					    #region 属性,变量等
 | 
				
			||||||
@@ -55,32 +48,30 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public List<string> Variables = new();
 | 
					    public List<string> Variables = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private readonly Action<byte, object, string, Exception> _logAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 当前的变量名称/OPC变量节点
 | 
					    /// 当前的变量名称/OPC变量节点
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private readonly Dictionary<string, VariableNode> _variableDicts = new();
 | 
					    private readonly Dictionary<string, VariableNode> _variableDicts = new();
 | 
				
			||||||
    private readonly EasyLock checkLock = new();
 | 
					    private readonly object checkLock = new();
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 当前的订阅组,组名称/组
 | 
					    /// 当前的订阅组,组名称/组
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private readonly Dictionary<string, Subscription> dic_subscriptions = new();
 | 
					    private readonly Dictionary<string, Subscription> dic_subscriptions = new();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private readonly ILog Log;
 | 
					 | 
				
			||||||
    private readonly ApplicationInstance m_application = new();
 | 
					    private readonly ApplicationInstance m_application = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private readonly ApplicationConfiguration m_configuration;
 | 
					    private readonly ApplicationConfiguration m_configuration;
 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// SessionReconnectHandler
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    public SessionReconnectHandler ReConnectHandler => m_reConnectHandler;
 | 
					 | 
				
			||||||
    private SessionReconnectHandler m_reConnectHandler;
 | 
					    private SessionReconnectHandler m_reConnectHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ISession m_session;
 | 
					    private ISession m_session;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 默认的构造函数,实例化一个新的OPC UA类
 | 
					    /// 默认的构造函数,实例化一个新的OPC UA类
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public OPCUAClient(ILog log)
 | 
					    public OPCUAClient(Action<byte, object, string, Exception> log)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Log = log;
 | 
					        _logAction = log;
 | 
				
			||||||
        var certificateValidator = new CertificateValidator();
 | 
					        var certificateValidator = new CertificateValidator();
 | 
				
			||||||
        certificateValidator.CertificateValidation += CertificateValidation;
 | 
					        certificateValidator.CertificateValidation += CertificateValidation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,6 +184,10 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public string OPCUAName { get; set; } = "ThingsGateway";
 | 
					    public string OPCUAName { get; set; } = "ThingsGateway";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// SessionReconnectHandler
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public SessionReconnectHandler ReConnectHandler => m_reConnectHandler;
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 当前活动会话。
 | 
					    /// 当前活动会话。
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -236,7 +231,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Log.Error($"初始化{items[i]}变量订阅失败" + ex.Message);
 | 
					                _logAction?.Invoke(3, this, $"初始化{items[i]}变量订阅失败", ex);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        m_subscription.AddItems(monitoredItems);
 | 
					        m_subscription.AddItems(monitoredItems);
 | 
				
			||||||
@@ -249,10 +244,12 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        m_subscription.ApplyChanges();
 | 
					        m_subscription.ApplyChanges();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var iserror = m_subscription.MonitoredItems.Any(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode));
 | 
					        var isError = m_subscription.MonitoredItems.Any(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode));
 | 
				
			||||||
        if (iserror)
 | 
					        if (isError)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Log.Error("创建以下变量订阅失败" + 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());
 | 
					            _logAction?.Invoke(3, this, $"创建以下变量订阅失败:{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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        lock (dic_subscriptions)
 | 
					        lock (dic_subscriptions)
 | 
				
			||||||
@@ -262,7 +259,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
                // remove
 | 
					                // remove
 | 
				
			||||||
                dic_subscriptions[subscriptionName].Delete(true);
 | 
					                dic_subscriptions[subscriptionName].Delete(true);
 | 
				
			||||||
                m_session.RemoveSubscription(dic_subscriptions[subscriptionName]);
 | 
					                m_session.RemoveSubscription(dic_subscriptions[subscriptionName]);
 | 
				
			||||||
                dic_subscriptions[subscriptionName].SafeDispose();
 | 
					                try { dic_subscriptions[subscriptionName].Dispose(); } catch { }
 | 
				
			||||||
                dic_subscriptions[subscriptionName] = m_subscription;
 | 
					                dic_subscriptions[subscriptionName] = m_subscription;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
@@ -283,7 +280,8 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                item.Value.Delete(true);
 | 
					                item.Value.Delete(true);
 | 
				
			||||||
                m_session.RemoveSubscription(item.Value);
 | 
					                m_session.RemoveSubscription(item.Value);
 | 
				
			||||||
                item.Value.SafeDispose();
 | 
					                try { item.Value.Dispose(); } catch { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            dic_subscriptions.Clear();
 | 
					            dic_subscriptions.Clear();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -302,7 +300,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
                // remove
 | 
					                // remove
 | 
				
			||||||
                dic_subscriptions[subscriptionName].Delete(true);
 | 
					                dic_subscriptions[subscriptionName].Delete(true);
 | 
				
			||||||
                m_session.RemoveSubscription(dic_subscriptions[subscriptionName]);
 | 
					                m_session.RemoveSubscription(dic_subscriptions[subscriptionName]);
 | 
				
			||||||
                dic_subscriptions[subscriptionName].SafeDispose();
 | 
					                try { dic_subscriptions[subscriptionName].Dispose(); } catch { }
 | 
				
			||||||
                dic_subscriptions.RemoveWhere(a => a.Key == subscriptionName);
 | 
					                dic_subscriptions.RemoveWhere(a => a.Key == subscriptionName);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -321,7 +319,8 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
                    var data = 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)
 | 
					                    if (data == null && value.Value != null)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        Log.Warning($"{monitoreditem.StartNodeId}转换出错,原始值String为{value.Value}");
 | 
					                        _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);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    DataChangedHandler?.Invoke((variableNode, value, data));
 | 
					                    DataChangedHandler?.Invoke((variableNode, value, data));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -335,7 +334,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (Exception ex)
 | 
					        catch (Exception ex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Log.Warning($"{monitoreditem.StartNodeId}订阅事件出错:{ex.Message}");
 | 
					            _logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}订阅处理错误", ex);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -417,9 +416,9 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    /// <param name="end">结束时间</param>
 | 
					    /// <param name="end">结束时间</param>
 | 
				
			||||||
    /// <param name="count">读取的个数</param>
 | 
					    /// <param name="count">读取的个数</param>
 | 
				
			||||||
    /// <param name="containBound">是否包含边界</param>
 | 
					    /// <param name="containBound">是否包含边界</param>
 | 
				
			||||||
    /// <param name="token">token</param>
 | 
					    /// <param name="cancellationToken">cancellationToken</param>
 | 
				
			||||||
    /// <returns>读取的数据列表</returns>
 | 
					    /// <returns>读取的数据列表</returns>
 | 
				
			||||||
    public async Task<List<DataValue>> ReadHistoryRawDataValues(string tag, DateTime start, DateTime end, uint count = 1, bool containBound = false, CancellationToken token = default)
 | 
					    public async Task<List<DataValue>> ReadHistoryRawDataValues(string tag, DateTime start, DateTime end, uint count = 1, bool containBound = false, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        HistoryReadValueId m_nodeToContinue = new()
 | 
					        HistoryReadValueId m_nodeToContinue = new()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -446,7 +445,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
             TimestampsToReturn.Both,
 | 
					             TimestampsToReturn.Both,
 | 
				
			||||||
             false,
 | 
					             false,
 | 
				
			||||||
             nodesToRead,
 | 
					             nodesToRead,
 | 
				
			||||||
             token);
 | 
					             cancellationToken);
 | 
				
			||||||
        var results = result.Results;
 | 
					        var results = result.Results;
 | 
				
			||||||
        var diagnosticInfos = result.DiagnosticInfos;
 | 
					        var diagnosticInfos = result.DiagnosticInfos;
 | 
				
			||||||
        ClientBase.ValidateResponse(results, nodesToRead);
 | 
					        ClientBase.ValidateResponse(results, nodesToRead);
 | 
				
			||||||
@@ -465,12 +464,15 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region 连接
 | 
					    #region 连接
 | 
				
			||||||
 | 
					    private ComplexTypeSystem typeSystem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 连接到服务器
 | 
					    /// 连接到服务器
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public async Task ConnectAsync()
 | 
					    public async Task ConnectAsync()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        await ConnectAsync(OPCNode.OPCUrl);
 | 
					        await ConnectAsync(OPCNode.OPCUrl);
 | 
				
			||||||
 | 
					        _logAction?.Invoke(1, this, $"连接成功", null);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -482,11 +484,10 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        // disconnect any existing session.
 | 
					        // disconnect any existing session.
 | 
				
			||||||
        if (m_session != null)
 | 
					        if (m_session != null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Log.Debug("断开连接");
 | 
					            _logAction?.Invoke(1, this, $"主动断开连接", null);
 | 
				
			||||||
            m_session = null;
 | 
					            m_session = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private ComplexTypeSystem typeSystem;
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Creates a new session.
 | 
					    /// Creates a new session.
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -504,7 +505,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
 | 
					        EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
 | 
				
			||||||
        ConfiguredEndpoint endpoint = new(null, endpointDescription, endpointConfiguration);
 | 
					        ConfiguredEndpoint endpoint = new(null, endpointDescription, endpointConfiguration);
 | 
				
			||||||
        UserIdentity userIdentity;
 | 
					        UserIdentity userIdentity;
 | 
				
			||||||
        if (!OPCNode.UserName.IsNullOrEmpty())
 | 
					        if (!string.IsNullOrEmpty(OPCNode.UserName))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            userIdentity = new UserIdentity(OPCNode.UserName, OPCNode.Password);
 | 
					            userIdentity = new UserIdentity(OPCNode.UserName, OPCNode.Password);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -525,7 +526,6 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    Array.Empty<string>());
 | 
					    Array.Empty<string>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        typeSystem = new ComplexTypeSystem(m_session);
 | 
					        typeSystem = new ComplexTypeSystem(m_session);
 | 
				
			||||||
        Log.Debug("连接成功");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;
 | 
					        m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;
 | 
				
			||||||
        m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
 | 
					        m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
 | 
				
			||||||
@@ -538,10 +538,9 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private void PrivateDisconnect()
 | 
					    private void PrivateDisconnect()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // stop any reconnect operation.
 | 
					 | 
				
			||||||
        if (m_reConnectHandler != null)
 | 
					        if (m_reConnectHandler != null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            m_reConnectHandler.SafeDispose();
 | 
					            try { m_reConnectHandler.Dispose(); } catch { }
 | 
				
			||||||
            m_reConnectHandler = null;
 | 
					            m_reConnectHandler = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (m_session != null)
 | 
					        if (m_session != null)
 | 
				
			||||||
@@ -556,23 +555,21 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #region 读取/写入
 | 
					    #region 读取/写入
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 从服务器读取值
 | 
					    /// 从服务器读取值
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public async Task<List<(string, DataValue, JToken)>> ReadJTokenValueAsync(string[] tags, CancellationToken token = default)
 | 
					    public async Task<List<(string, DataValue, JToken)>> ReadJTokenValueAsync(string[] tags, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var result = await ReadJTokenValueAsync(tags.Select(a => new NodeId(a)).ToArray(), token);
 | 
					        var result = await ReadJTokenValueAsync(tags.Select(a => new NodeId(a)).ToArray(), cancellationToken);
 | 
				
			||||||
        return result;
 | 
					        return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 异步写opc标签
 | 
					    /// 异步写opc标签
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public async Task<Dictionary<string, OperResult>> WriteNodeAsync(Dictionary<string, JToken> writeInfoLists, CancellationToken token = default)
 | 
					    public async Task<Dictionary<string, Tuple<bool, string>>> WriteNodeAsync(Dictionary<string, JToken> writeInfoLists, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Dictionary<string, OperResult> results = new();
 | 
					        Dictionary<string, Tuple<bool, string>> results = new();
 | 
				
			||||||
        try
 | 
					        try
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            WriteValueCollection valuesToWrite = new();
 | 
					            WriteValueCollection valuesToWrite = new();
 | 
				
			||||||
@@ -583,7 +580,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
                    NodeId = new NodeId(item.Key),
 | 
					                    NodeId = new NodeId(item.Key),
 | 
				
			||||||
                    AttributeId = Attributes.Value,
 | 
					                    AttributeId = Attributes.Value,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                var variableNode = await ReadNodeAsync(item.Key, false, token);
 | 
					                var variableNode = await ReadNodeAsync(item.Key, false, cancellationToken);
 | 
				
			||||||
                var dataValue = JsonUtils.Decode(
 | 
					                var dataValue = JsonUtils.Decode(
 | 
				
			||||||
                    m_session.MessageContext,
 | 
					                    m_session.MessageContext,
 | 
				
			||||||
                    variableNode.DataType,
 | 
					                    variableNode.DataType,
 | 
				
			||||||
@@ -599,7 +596,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var result = await m_session.WriteAsync(
 | 
					            var result = await m_session.WriteAsync(
 | 
				
			||||||
     requestHeader: null,
 | 
					     requestHeader: null,
 | 
				
			||||||
     nodesToWrite: valuesToWrite, token);
 | 
					     nodesToWrite: valuesToWrite, cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ClientBase.ValidateResponse(result.Results, valuesToWrite);
 | 
					            ClientBase.ValidateResponse(result.Results, valuesToWrite);
 | 
				
			||||||
            ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, valuesToWrite);
 | 
					            ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, valuesToWrite);
 | 
				
			||||||
@@ -609,10 +606,10 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
            for (int i = 0; i < keys.Count; i++)
 | 
					            for (int i = 0; i < keys.Count; i++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!StatusCode.IsGood(result.Results[i]))
 | 
					                if (!StatusCode.IsGood(result.Results[i]))
 | 
				
			||||||
                    results.Add(keys[i], new(result.Results[i].ToString()));
 | 
					                    results.Add(keys[i], Tuple.Create(true, result.Results[i].ToString()));
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    results.Add(keys[i], OperResult.CreateSuccessResult());
 | 
					                    results.Add(keys[i], Tuple.Create(false, "成功"));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -623,7 +620,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
            var keys = writeInfoLists.Keys.ToList();
 | 
					            var keys = writeInfoLists.Keys.ToList();
 | 
				
			||||||
            foreach (var item in keys)
 | 
					            foreach (var item in keys)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                results.Add(item, new(ex));
 | 
					                results.Add(item, Tuple.Create(true, ex.Message));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return results;
 | 
					            return results;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -633,7 +630,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 从服务器读取值
 | 
					    /// 从服务器读取值
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private async Task<List<(string, DataValue, JToken)>> ReadJTokenValueAsync(NodeId[] nodeIds, CancellationToken token = default)
 | 
					    private async Task<List<(string, DataValue, JToken)>> ReadJTokenValueAsync(NodeId[] nodeIds, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (m_session == null)
 | 
					        if (m_session == null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -655,7 +652,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
             0,
 | 
					             0,
 | 
				
			||||||
             TimestampsToReturn.Neither,
 | 
					             TimestampsToReturn.Neither,
 | 
				
			||||||
             nodesToRead,
 | 
					             nodesToRead,
 | 
				
			||||||
             token);
 | 
					             cancellationToken);
 | 
				
			||||||
        var results = result.Results;
 | 
					        var results = result.Results;
 | 
				
			||||||
        var diagnosticInfos = result.DiagnosticInfos;
 | 
					        var diagnosticInfos = result.DiagnosticInfos;
 | 
				
			||||||
        ClientBase.ValidateResponse(results, nodesToRead);
 | 
					        ClientBase.ValidateResponse(results, nodesToRead);
 | 
				
			||||||
@@ -663,7 +660,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        List<(string, DataValue, JToken)> jTokens = new();
 | 
					        List<(string, DataValue, JToken)> jTokens = new();
 | 
				
			||||||
        for (int i = 0; i < results.Count; i++)
 | 
					        for (int i = 0; i < results.Count; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var variableNode = await ReadNodeAsync(nodeIds[i].ToString(), false, token);
 | 
					            var variableNode = await ReadNodeAsync(nodeIds[i].ToString(), false, cancellationToken);
 | 
				
			||||||
            var type = TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable);
 | 
					            var type = TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable);
 | 
				
			||||||
            var jToken = JsonUtils.Encode(m_session.MessageContext, type, results[i].Value);
 | 
					            var jToken = JsonUtils.Encode(m_session.MessageContext, type, results[i].Value);
 | 
				
			||||||
            jTokens.Add((variableNode.NodeId.ToString(), results[i], jToken));
 | 
					            jTokens.Add((variableNode.NodeId.ToString(), results[i], jToken));
 | 
				
			||||||
@@ -674,7 +671,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 从服务器或缓存读取节点
 | 
					    /// 从服务器或缓存读取节点
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private async Task<VariableNode> ReadNodeAsync(string nodeIdStr, bool isOnlyServer = true, CancellationToken token = default)
 | 
					    private async Task<VariableNode> ReadNodeAsync(string nodeIdStr, bool isOnlyServer = true, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (!isOnlyServer)
 | 
					        if (!isOnlyServer)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -685,7 +682,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        NodeId nodeToRead = new(nodeIdStr);
 | 
					        NodeId nodeToRead = new(nodeIdStr);
 | 
				
			||||||
        var node = (VariableNode)await m_session.ReadNodeAsync(nodeToRead, token);
 | 
					        var node = (VariableNode)await m_session.ReadNodeAsync(nodeToRead, cancellationToken);
 | 
				
			||||||
        await typeSystem.LoadType(node.DataType, true, true);
 | 
					        await typeSystem.LoadType(node.DataType, true, true);
 | 
				
			||||||
        _variableDicts.AddOrUpdate(nodeIdStr, node);
 | 
					        _variableDicts.AddOrUpdate(nodeIdStr, node);
 | 
				
			||||||
        return node;
 | 
					        return node;
 | 
				
			||||||
@@ -698,7 +695,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 读取一个节点的所有属性
 | 
					    /// 读取一个节点的所有属性
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public async Task<OperResult<List<OPCNodeAttribute>>> ReadNoteAttributeAsync(string tag, uint attributesId, CancellationToken token = default)
 | 
					    public async Task<List<OPCNodeAttribute>> ReadNoteAttributeAsync(string tag, uint attributesId, CancellationToken cancellationToken = default)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        BrowseDescriptionCollection nodesToBrowse = new();
 | 
					        BrowseDescriptionCollection nodesToBrowse = new();
 | 
				
			||||||
        ReadValueIdCollection nodesToRead = new();
 | 
					        ReadValueIdCollection nodesToRead = new();
 | 
				
			||||||
@@ -721,16 +718,16 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
        nodesToBrowse.Add(nodeToBrowse);
 | 
					        nodesToBrowse.Add(nodeToBrowse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var result1 = await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, token);
 | 
					        var result1 = await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, cancellationToken);
 | 
				
			||||||
        var result2 = result1.Copy<List<OPCNodeAttribute>>();
 | 
					
 | 
				
			||||||
        result2.Content = result1.Content?.Values?.FirstOrDefault()?.ToList();
 | 
					        var result2 = result1.Values.FirstOrDefault();
 | 
				
			||||||
        return result2;
 | 
					        return result2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 读取节点的所有属性
 | 
					    /// 读取节点的所有属性
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public async Task<OperResult<Dictionary<string, List<OPCNodeAttribute>>>> ReadNoteAttributeAsync(List<string> tags, CancellationToken token)
 | 
					    public async Task<Dictionary<string, List<OPCNodeAttribute>>> ReadNoteAttributeAsync(List<string> tags, CancellationToken cancellationToken)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        BrowseDescriptionCollection nodesToBrowse = new();
 | 
					        BrowseDescriptionCollection nodesToBrowse = new();
 | 
				
			||||||
        ReadValueIdCollection nodesToRead = new();
 | 
					        ReadValueIdCollection nodesToRead = new();
 | 
				
			||||||
@@ -760,7 +757,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, token);
 | 
					        return await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, cancellationToken);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -926,11 +923,9 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <inheritdoc/>
 | 
					    /// <inheritdoc/>
 | 
				
			||||||
    protected override void Dispose(bool disposing)
 | 
					    public void Dispose()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Disconnect();
 | 
					        Disconnect();
 | 
				
			||||||
        checkLock.SafeDispose();
 | 
					 | 
				
			||||||
        base.Dispose(disposing);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region 私有方法
 | 
					    #region 私有方法
 | 
				
			||||||
@@ -946,15 +941,15 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private async Task<OperResult<Dictionary<string, List<OPCNodeAttribute>>>> ReadNoteAttributeAsync(BrowseDescriptionCollection nodesToBrowse, ReadValueIdCollection nodesToRead, CancellationToken token)
 | 
					    private async Task<Dictionary<string, List<OPCNodeAttribute>>> ReadNoteAttributeAsync(BrowseDescriptionCollection nodesToBrowse, ReadValueIdCollection nodesToRead, CancellationToken cancellationToken)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int startOfProperties = nodesToRead.Count;
 | 
					        int startOfProperties = nodesToRead.Count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ReferenceDescriptionCollection references = await FormUtils.BrowseAsync(m_session, nodesToBrowse, false, token);
 | 
					        ReferenceDescriptionCollection references = await FormUtils.BrowseAsync(m_session, nodesToBrowse, false, cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (references == null)
 | 
					        if (references == null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new OperResult<Dictionary<string, List<OPCNodeAttribute>>>("浏览失败");
 | 
					            throw new("浏览失败");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (int ii = 0; ii < references.Count; ii++)
 | 
					        for (int ii = 0; ii < references.Count; ii++)
 | 
				
			||||||
@@ -976,7 +971,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
            null,
 | 
					            null,
 | 
				
			||||||
            0,
 | 
					            0,
 | 
				
			||||||
            TimestampsToReturn.Neither,
 | 
					            TimestampsToReturn.Neither,
 | 
				
			||||||
            nodesToRead, token);
 | 
					            nodesToRead, cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ClientBase.ValidateResponse(result.Results, nodesToRead);
 | 
					        ClientBase.ValidateResponse(result.Results, nodesToRead);
 | 
				
			||||||
        ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, nodesToRead);
 | 
					        ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, nodesToRead);
 | 
				
			||||||
@@ -1032,8 +1027,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
                nodeAttributes.Add(nodeToRead.NodeId.ToString(), new() { item });
 | 
					                nodeAttributes.Add(nodeToRead.NodeId.ToString(), new() { item });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return nodeAttributes;
 | 
				
			||||||
        return OperResult.CreateSuccessResult(nodeAttributes);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -1047,17 +1041,15 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        m_session = m_reConnectHandler.Session;
 | 
					        m_session = m_reConnectHandler.Session;
 | 
				
			||||||
        m_reConnectHandler.SafeDispose();
 | 
					 | 
				
			||||||
        m_reConnectHandler = null;
 | 
					        m_reConnectHandler = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
 | 
					    private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (checkLock.IsWaitting) { return; }
 | 
					        lock (checkLock)
 | 
				
			||||||
        checkLock.Wait();
 | 
					 | 
				
			||||||
        try
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!Object.ReferenceEquals(session, m_session))
 | 
					            if (!Object.ReferenceEquals(session, m_session))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
@@ -1065,7 +1057,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (ServiceResult.IsBad(e.Status))
 | 
					            if (ServiceResult.IsBad(e.Status))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Log.Warning($"心跳检测错误:{e.Status}");
 | 
					                _logAction?.Invoke(3, this, $"心跳检测错误:{e.Status}", null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (m_reConnectHandler == null)
 | 
					                if (m_reConnectHandler == null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -1076,11 +1068,7 @@ public class OPCUAClient : DisposableObject
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Log.Trace($"心跳检测正常 [{session.Endpoint.EndpointUrl}]");
 | 
					
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        finally
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            checkLock.Release();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<PropertyGroup>
 | 
				
			||||||
 | 
							<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						</PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<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" />
 | 
				
			||||||
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
@@ -53,7 +53,7 @@
 | 
				
			|||||||
            <param name="session"></param>
 | 
					            <param name="session"></param>
 | 
				
			||||||
            <param name="nodesToBrowse"></param>
 | 
					            <param name="nodesToBrowse"></param>
 | 
				
			||||||
            <param name="throwOnError"></param>
 | 
					            <param name="throwOnError"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
            <exception cref="T:Opc.Ua.ServiceResultException"></exception>
 | 
					            <exception cref="T:Opc.Ua.ServiceResultException"></exception>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
@@ -64,7 +64,7 @@
 | 
				
			|||||||
            <param name="session"></param>
 | 
					            <param name="session"></param>
 | 
				
			||||||
            <param name="nodeToBrowse"></param>
 | 
					            <param name="nodeToBrowse"></param>
 | 
				
			||||||
            <param name="throwOnError"></param>
 | 
					            <param name="throwOnError"></param>
 | 
				
			||||||
            <param name="token"></param>
 | 
					            <param name="cancellationToken"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
            <exception cref="T:Opc.Ua.ServiceResultException"></exception>
 | 
					            <exception cref="T:Opc.Ua.ServiceResultException"></exception>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
@@ -304,7 +304,7 @@
 | 
				
			|||||||
            SessionReconnectHandler
 | 
					            SessionReconnectHandler
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.#ctor(TouchSocket.Core.ILog)">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.#ctor(ThingsGateway.Foundation.ILog)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            默认的构造函数,实例化一个新的OPC UA类
 | 
					            默认的构造函数,实例化一个新的OPC UA类
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
@@ -375,7 +375,7 @@
 | 
				
			|||||||
            <param name="end">结束时间</param>
 | 
					            <param name="end">结束时间</param>
 | 
				
			||||||
            <param name="count">读取的个数</param>
 | 
					            <param name="count">读取的个数</param>
 | 
				
			||||||
            <param name="containBound">是否包含边界</param>
 | 
					            <param name="containBound">是否包含边界</param>
 | 
				
			||||||
            <param name="token">token</param>
 | 
					            <param name="cancellationToken">cancellationToken</param>
 | 
				
			||||||
            <returns>读取的数据列表</returns>
 | 
					            <returns>读取的数据列表</returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ConnectAsync">
 | 
					        <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ConnectAsync">
 | 
				
			||||||
@@ -10,10 +10,6 @@
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ThingsGateway.Foundation.Adapter.OPCUA;
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCUA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal static class CollectionExtensions
 | 
					internal static class CollectionExtensions
 | 
				
			||||||
@@ -24,7 +20,7 @@ internal static class CollectionExtensions
 | 
				
			|||||||
    /// <typeparam name="T"></typeparam>
 | 
					    /// <typeparam name="T"></typeparam>
 | 
				
			||||||
    /// <param name="this"></param>
 | 
					    /// <param name="this"></param>
 | 
				
			||||||
    /// <param name="where"></param>
 | 
					    /// <param name="where"></param>
 | 
				
			||||||
    public static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
 | 
					    internal static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        foreach (var obj in @this.Where(where).ToList())
 | 
					        foreach (var obj in @this.Where(where).ToList())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -39,7 +35,7 @@ internal static class CollectionExtensions
 | 
				
			|||||||
    /// <param name="source"></param>
 | 
					    /// <param name="source"></param>
 | 
				
			||||||
    /// <param name="selector"></param>
 | 
					    /// <param name="selector"></param>
 | 
				
			||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector)
 | 
					    internal static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return Task.WhenAll(source.Select(selector));
 | 
					        return Task.WhenAll(source.Select(selector));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					#region copyright
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
				
			||||||
 | 
					//  使用文档:https://diego2098.gitee.io/thingsgateway-docs/
 | 
				
			||||||
 | 
					//  QQ群:605534569
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
 | 
				
			||||||
 | 
					//  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
 | 
				
			||||||
 | 
					//  CSDN博客:https://blog.csdn.net/qq_40374647
 | 
				
			||||||
 | 
					//  哔哩哔哩视频:https://space.bilibili.com/94253567
 | 
				
			||||||
 | 
					//  Gitee源代码仓库:https://gitee.com/RRQM_Home
 | 
				
			||||||
 | 
					//  Github源代码仓库:https://github.com/RRQM
 | 
				
			||||||
 | 
					//  API首页:http://rrqm_home.gitee.io/touchsocket/
 | 
				
			||||||
 | 
					//  交流QQ群:234762506
 | 
				
			||||||
 | 
					//  感谢您的下载和使用
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ThingsGateway.Foundation.Adapter.OPCUA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// DictionaryExtension
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					internal static class DictionaryExtension
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    #region 字典扩展
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 移除满足条件的项目。
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="TKey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="pairs"></param>
 | 
				
			||||||
 | 
					    /// <param name="func"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static int RemoveWhen<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> pairs, Func<KeyValuePair<TKey, TValue>, bool> func)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var list = new List<TKey>();
 | 
				
			||||||
 | 
					        foreach (var item in pairs)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (func?.Invoke(item) == true)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                list.Add(item.Key);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var count = 0;
 | 
				
			||||||
 | 
					        foreach (var item in list)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (pairs.TryRemove(item, out _))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                count++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return count;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if NET45_OR_GREATER || NETSTANDARD2_0_OR_GREATER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 尝试添加
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="Tkey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="dictionary"></param>
 | 
				
			||||||
 | 
					    /// <param name="tkey"></param>
 | 
				
			||||||
 | 
					    /// <param name="value"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static bool TryAdd<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (dictionary.ContainsKey(tkey))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dictionary.Add(tkey, value);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 尝试添加
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="Tkey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="dictionary"></param>
 | 
				
			||||||
 | 
					    /// <param name="tkey"></param>
 | 
				
			||||||
 | 
					    /// <param name="value"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static void AddOrUpdate<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (dictionary.ContainsKey(tkey))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            dictionary[tkey] = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            dictionary.Add(tkey, value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 获取值。如果键不存在,则返回默认值。
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="Tkey"></typeparam>
 | 
				
			||||||
 | 
					    /// <typeparam name="TValue"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="dictionary"></param>
 | 
				
			||||||
 | 
					    /// <param name="tkey"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    internal static TValue GetValue<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return dictionary.TryGetValue(tkey, out var value) ? value : default;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #endregion 字典扩展
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user