mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-30 23:24:00 +08:00 
			
		
		
		
	Compare commits
	
		
			39 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 65c695d9ce | ||
|   | 57253fe46a | ||
|   | 4e5c443440 | ||
|   | 0b3b73d8ec | ||
|   | 921eabc134 | ||
|   | 0faa428751 | ||
|   | f71a2fdd63 | ||
|   | 4eb9ed8aba | ||
|   | d7b549abb8 | ||
|   | 95d723c578 | ||
|   | 2fcd853e86 | ||
|   | 07eef7c812 | ||
|   | b01e0757fa | ||
|   | 32844a20c6 | ||
|   | 5b6532c601 | ||
|   | 2c5b4b4027 | ||
|   | 72d7ecf195 | ||
|   | 2cfa6b4306 | ||
|   | 6f6ffde0ab | ||
|   | 1694739a16 | ||
|   | 95d1e8bfca | ||
|   | 60dec08e3c | ||
|   | a99d71be93 | ||
|   | f1331b6a0c | ||
|   | 10d66b642b | ||
|   | cd2310e4a8 | ||
|   | 1b399cf6b0 | ||
|   | 877445bc0a | ||
|   | 9a5b345bde | ||
|   | fc9e8ea7b3 | ||
|   | 32be6fcfc1 | ||
|   | 49847236c2 | ||
|   | d8424443e6 | ||
|   | f3b571ec3f | ||
|   | 99318bb5d7 | ||
|   | 1aa154c9aa | ||
|   | c65d8a445b | ||
|   | 80f4f85570 | ||
|   | 5beee43a6b | 
| @@ -22,7 +22,9 @@ | ||||
|  | ||||
| [ThingsGateway演示地址](http://120.24.62.140:5000/) | ||||
|  | ||||
| 账户	:  **superAdmin**	密码 : **111111** | ||||
| 账户	:  **superAdmin**	 | ||||
|  | ||||
| 密码 : **111111** | ||||
|  | ||||
| ## 赞助 | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <Project> | ||||
| 	<PropertyGroup> | ||||
| 		<TargetFrameworks>net6.0;net7.0</TargetFrameworks> | ||||
| 		<Version>2.0.6.0</Version> | ||||
| 		<Version>2.1.0.0</Version> | ||||
| 		<Authors>Diego</Authors> | ||||
| 		<Product>ThingsGateway</Product> | ||||
| 		<Copyright>© 2023-present Diego</Copyright> | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -20,19 +20,19 @@ namespace ThingsGateway.Admin.Blazor.Core; | ||||
| public partial class AppBarItems | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 链接 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT_URL { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>Ȩ | ||||
|     /// 版权 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 标题 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_TITLE { get; set; } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Components; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor.Core; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>/ͣ<><CDA3> <20>ı<EFBFBD><C4B1><EFBFBD>ʾ | ||||
| /// 启用/停用 文本提示 | ||||
| /// </summary> | ||||
| public partial class EnableChip | ||||
| { | ||||
| @@ -46,5 +46,5 @@ public partial class EnableChip | ||||
|  | ||||
|     private string TextColor => Value ? "green" : "error"; | ||||
|     private string Color => Value ? "green-lighten" : "warning-lighten"; | ||||
|     private string Label => Value ? EnabledLabel ?? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : DisabledLabel ?? "ͣ<EFBFBD><EFBFBD>"; | ||||
|     private string Label => Value ? EnabledLabel ?? "启用" : DisabledLabel ?? "停用"; | ||||
| } | ||||
| @@ -1,18 +1,18 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor.Core; | ||||
| /// <summary> | ||||
| /// <EFBFBD>ղ<EFBFBD>/<2F><><EFBFBD>ݷ<EFBFBD>ʽ | ||||
| /// 收藏/快捷方式 | ||||
| /// </summary> | ||||
| public partial class Favorite | ||||
| { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -22,17 +22,17 @@ public partial class Foter | ||||
| { | ||||
|     private string Version = ""; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 链接 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT_URL { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>Ȩ | ||||
|     /// 版权 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 标题 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_TITLE { get; set; } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -20,23 +20,23 @@ namespace ThingsGateway.Admin.Blazor.Core; | ||||
| public partial class Logo | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Logo<EFBFBD>߶<EFBFBD> | ||||
|     /// Logo高度 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public int HeightInt { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 链接 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT_URL { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>Ȩ | ||||
|     /// 版权 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 标题 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_TITLE { get; set; } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -34,7 +34,7 @@ public partial class PageTabs | ||||
|         return op; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Tabsʵ<EFBFBD><EFBFBD> | ||||
|     /// Tabs实例 | ||||
|     /// </summary> | ||||
|     public PPageTabs PPageTabs { get; private set; } | ||||
|  | ||||
| @@ -46,7 +46,7 @@ public partial class PageTabs | ||||
|     [Parameter] | ||||
|     public IEnumerable<string> SelfPatterns { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 子组件 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -49,11 +49,11 @@ public partial class UserMenu | ||||
|         var ret = str?.ToJsonWithT<UnifyResult<string>>(); | ||||
|         if (ret?.Code != 200) | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync("ע<EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>", AlertTypes.Error); | ||||
|             await PopupService.EnqueueSnackbarAsync("注销失败", AlertTypes.Error); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync("ע<EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|             await PopupService.EnqueueSnackbarAsync("注销成功", AlertTypes.Success); | ||||
|             await Task.Delay(500); | ||||
|             NavigationManager.NavigateTo(NavigationManager.Uri); | ||||
|         } | ||||
|   | ||||
| @@ -0,0 +1,68 @@ | ||||
| #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 Furion.DependencyInjection; | ||||
|  | ||||
| namespace BlazorComponent.I18n; | ||||
| /// <summary> | ||||
| /// CookieStorage | ||||
| /// </summary> | ||||
| public class CookieStorage : IScoped | ||||
| { | ||||
|     private readonly IJSRuntime _jsRuntime; | ||||
|     /// <summary> | ||||
|     /// CookieStorage | ||||
|     /// </summary> | ||||
|     /// <param name="jsRuntime"></param> | ||||
|     public CookieStorage(IJSRuntime jsRuntime) | ||||
|     { | ||||
|         _jsRuntime = jsRuntime; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// GetCookieAsync | ||||
|     /// </summary> | ||||
|     /// <param name="key"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<string> GetCookieAsync(string key) | ||||
|     { | ||||
|         return await _jsRuntime.InvokeAsync<string>(JsInteropConstants.GetCookie, key); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// GetCookie | ||||
|     /// </summary> | ||||
|     /// <param name="key"></param> | ||||
|     /// <returns></returns> | ||||
|     public string GetCookie(string key) | ||||
|     { | ||||
|         if (_jsRuntime is IJSInProcessRuntime jsInProcess) | ||||
|         { | ||||
|             return jsInProcess.Invoke<string>(JsInteropConstants.GetCookie, key); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// SetItemAsync | ||||
|     /// </summary> | ||||
|     /// <typeparam name="T"></typeparam> | ||||
|     /// <param name="key"></param> | ||||
|     /// <param name="value"></param> | ||||
|     public async void SetItemAsync<T>(string key, T value) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await _jsRuntime.InvokeVoidAsync(JsInteropConstants.SetCookie, key, value?.ToString()); | ||||
|         } | ||||
|         catch | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using BlazorComponent; | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Masa.Blazor; | ||||
| @@ -61,6 +63,8 @@ public class Startup : AppStartup | ||||
|  | ||||
|  | ||||
|             }); | ||||
|             options.Locale = new Locale("zh-CN", "en-US"); | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         services.AddScoped<InitTimezone>(); | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
|  | ||||
| 		<PackageReference Include="Masa.Blazor" Version="1.0.1" /> | ||||
| 		<PackageReference Include="Masa.Blazor" Version="1.0.2" /> | ||||
| 		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.10" /> | ||||
|  | ||||
| 	</ItemGroup> | ||||
|   | ||||
| @@ -857,5 +857,38 @@ | ||||
|             设置深浅主题统一由这个方法为入口 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:BlazorComponent.I18n.CookieStorage"> | ||||
|             <summary> | ||||
|             CookieStorage | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:BlazorComponent.I18n.CookieStorage.#ctor(Microsoft.JSInterop.IJSRuntime)"> | ||||
|             <summary> | ||||
|             CookieStorage | ||||
|             </summary> | ||||
|             <param name="jsRuntime"></param> | ||||
|         </member> | ||||
|         <member name="M:BlazorComponent.I18n.CookieStorage.GetCookieAsync(System.String)"> | ||||
|             <summary> | ||||
|             GetCookieAsync | ||||
|             </summary> | ||||
|             <param name="key"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:BlazorComponent.I18n.CookieStorage.GetCookie(System.String)"> | ||||
|             <summary> | ||||
|             GetCookie | ||||
|             </summary> | ||||
|             <param name="key"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:BlazorComponent.I18n.CookieStorage.SetItemAsync``1(System.String,``0)"> | ||||
|             <summary> | ||||
|             SetItemAsync | ||||
|             </summary> | ||||
|             <typeparam name="T"></typeparam> | ||||
|             <param name="key"></param> | ||||
|             <param name="value"></param> | ||||
|         </member> | ||||
|     </members> | ||||
| </doc> | ||||
|   | ||||
| @@ -153,7 +153,7 @@ public class UserResoures : IDisposable | ||||
|     { | ||||
|         if (MasaBlazor.Theme.Dark != isDark || isDark == null) | ||||
|             MasaBlazor.ToggleTheme(); | ||||
|         _cookieStorage?.SetItemAsync(BlazorResourceConst.ThemeCookieKey, isDark.ToJsonString()); | ||||
|         _cookieStorage?.SetItemAsync(BlazorResourceConst.ThemeCookieKey, MasaBlazor.Theme.Dark.ToJsonString()); | ||||
|     } | ||||
|  | ||||
|     private void InitCookie(IRequestCookieCollection cookies) | ||||
|   | ||||
| @@ -48,8 +48,7 @@ | ||||
|         var controllerTypes = App.EffectiveTypes. | ||||
|     Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass | ||||
|     && u.IsDefined(typeof(Microsoft.AspNetCore.Components.RouteAttribute), false)) | ||||
|     .Where(it => it.Assembly != typeof(BlazorApp).Assembly) | ||||
|     ; | ||||
|     .Where(it => it.Assembly != typeof(BlazorApp).Assembly); | ||||
|         var assemblys = controllerTypes?.Select(it => it.Assembly)?.Distinct(); | ||||
|         return assemblys; | ||||
|     } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -18,7 +18,7 @@ using ThingsGateway.Admin.Core; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD>ҳ | ||||
| /// 首页 | ||||
| /// </summary> | ||||
| public partial class Index | ||||
| { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -18,7 +18,7 @@ using ThingsGateway.Admin.Core; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| /// 个人设置 | ||||
| /// </summary> | ||||
| public partial class UserCenter | ||||
| { | ||||
| @@ -50,25 +50,25 @@ public partial class UserCenter | ||||
|     { | ||||
|         await UserCenterService.UpdateUserDefaultRazorAsync(UserManager.UserId, DefaultMenuId); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|  | ||||
|     async Task OnShortcutSaveAsync() | ||||
|     { | ||||
|         await UserCenterService.UpdateWorkbenchAsync(_menusChoice); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|     async Task OnUpdatePasswordInfoAsync(FormContext context) | ||||
|     { | ||||
|         var success = context.Validate(); | ||||
|         if (success) | ||||
|         { | ||||
|             //<EFBFBD><EFBFBD>֤<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD> | ||||
|             //验证成功,操作业务 | ||||
|             _passwordInfoInput.Id = UserResoures.CurrentUser.Id; | ||||
|             await UserCenterService.EditPasswordAsync(_passwordInfoInput); | ||||
|             await MainLayout.StateHasChangedAsync(); | ||||
|             await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>¼", AlertTypes.Success); | ||||
|             await PopupService.EnqueueSnackbarAsync("成功,将重新登录", AlertTypes.Success); | ||||
|             await Task.Delay(2000); | ||||
|             NavigationManager.NavigateTo(NavigationManager.Uri); | ||||
|         } | ||||
| @@ -78,6 +78,6 @@ public partial class UserCenter | ||||
|     { | ||||
|         await UserCenterService.UpdateUserInfoAsync(_updateInfoInput); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
| } | ||||
| @@ -9,10 +9,10 @@ | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.40" /> | ||||
| 		<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.40" /> | ||||
| 		<PackageReference Include="Furion.Pure" Version="4.8.8.40" /> | ||||
| 		<PackageReference Include="SqlSugarCore" Version="5.1.4.96" /> | ||||
| 		<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="Furion.Pure" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="SqlSugarCore" Version="5.1.4.102" /> | ||||
| 		<PackageReference Include="UAParser" Version="3.1.47" /> | ||||
| 		<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> | ||||
| 		<PackageReference Include="MiniExcel" Version="1.31.2" /> | ||||
|   | ||||
| @@ -89,13 +89,8 @@ public class RpcControler : IDynamicApiController | ||||
|     [Description("写入变量")] | ||||
|     public async Task<Dictionary<string, OperResult>> WriteDeviceMethods(Dictionary<string, string> objs) | ||||
|     { | ||||
|         Dictionary<string, OperResult> operResultDict = new(); | ||||
|         foreach (KeyValuePair<string, string> obj in objs) | ||||
|         { | ||||
|             var result = await RpcCore.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", obj); | ||||
|             operResultDict.Add(obj.Key, result); | ||||
|         } | ||||
|         return operResultDict; | ||||
|         var result = await RpcCore.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", objs); | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -36,6 +36,10 @@ public abstract class CollectBase : DriverBase | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public abstract bool IsSupportRequest { get; } | ||||
|     /// <summary> | ||||
|     /// 一般底层驱动,也有可能为null | ||||
|     /// </summary> | ||||
|     protected abstract IReadWriteDevice PLC { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 数据转换器 | ||||
| @@ -177,10 +181,22 @@ public abstract class CollectBase : DriverBase | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入变量值 | ||||
|     /// 批量写入变量值,需返回变量名称/结果 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public abstract Task<OperResult> WriteValueAsync(DeviceVariableRunTime deviceVariable, JToken value, CancellationToken token); | ||||
|     public virtual async Task<Dictionary<string, OperResult>> WriteValuesAsync(Dictionary<DeviceVariableRunTime, JToken> writeInfoLists, CancellationToken token) | ||||
|     { | ||||
|         if (PLC == null) | ||||
|             throw new("未初始化成功"); | ||||
|         Dictionary<string, OperResult> operResults = new(); | ||||
|         foreach (var writeInfo in writeInfoLists) | ||||
|         { | ||||
|             var result = await PLC.WriteAsync(writeInfo.Key.VariableAddress, writeInfo.Key.DataType, writeInfo.Value.ToString(), token); | ||||
|             await Task.Delay(10, token); //防止密集写入 | ||||
|             operResults.Add(writeInfo.Key.Name, result); | ||||
|         } | ||||
|         return operResults; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 初始化 | ||||
|   | ||||
| @@ -48,92 +48,172 @@ public class RpcSingletonService : ISingleton | ||||
|     /// 反向RPC入口方法 | ||||
|     /// </summary> | ||||
|     /// <param name="sourceDes">触发该方法的源说明</param> | ||||
|     /// <param name="item">指定键为变量名称,值为附带方法参数或写入值</param> | ||||
|     /// <param name="items">指定键为变量名称,值为附带方法参数或写入值</param> | ||||
|     /// <param name="isBlazor">如果是true,不检查<see cref="MemoryVariable.RpcWriteEnable"/>字段</param> | ||||
|     /// <param name="token"><see cref="CancellationToken"/> 取消源</param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> InvokeDeviceMethodAsync(string sourceDes, KeyValuePair<string, string> item, bool isBlazor = false, CancellationToken token = default) | ||||
|     public async Task<Dictionary<string, OperResult>> InvokeDeviceMethodAsync(string sourceDes, Dictionary<string, string> items, bool isBlazor = false, CancellationToken token = default) | ||||
|     { | ||||
|         //避免并发过高,这里延时10ms | ||||
|         await Task.Delay(10, token); | ||||
|         OperResult data = new(); | ||||
|         var tag = _globalDeviceData.AllVariables.FirstOrDefault(it => it.Name == item.Key); | ||||
|         if (tag == null) return new OperResult("不存在变量:" + item.Key); | ||||
|         if (tag.ProtectTypeEnum == ProtectTypeEnum.ReadOnly) return new OperResult("只读变量"); | ||||
|         if (!tag.RpcWriteEnable && !isBlazor) return new OperResult("不允许远程写入"); | ||||
|  | ||||
|         if (tag.IsMemoryVariable == true) | ||||
|         Dictionary<CollectDeviceCore, Dictionary<DeviceVariableRunTime, JToken>> WriteVariables = new(); | ||||
|         Dictionary<CollectDeviceCore, Dictionary<DeviceVariableRunTime, string>> WriteMethods = new(); | ||||
|         Dictionary<string, OperResult> results = new(); | ||||
|         foreach (var item in items) | ||||
|         { | ||||
|             return tag.SetValue(item.Value); | ||||
|         } | ||||
|         var dev = _collectDeviceHostService.CollectDeviceCores.FirstOrDefault(it => it.Device.Id == tag.DeviceId); | ||||
|         if (dev == null) return new OperResult("系统错误,不存在对应采集设备,请稍候重试"); | ||||
|         if (dev.Device.DeviceStatus == DeviceStatusEnum.OffLine) return new OperResult("设备已离线"); | ||||
|         if (dev.Device.DeviceStatus == DeviceStatusEnum.Pause) return new OperResult("设备已暂停"); | ||||
|         if (string.IsNullOrEmpty(tag.OtherMethod)) | ||||
|         { | ||||
|             //写入变量 | ||||
|             JToken tagValue; | ||||
|             try | ||||
|             { | ||||
|                 tagValue = JToken.Parse(item.Value); | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|                 tagValue = JToken.Parse("\"" + item.Value + "\""); | ||||
|             } | ||||
|  | ||||
|             data = await dev.InVokeWriteAsync(tag, tagValue, token); | ||||
|             _logQueues.Enqueue( | ||||
|                 new RpcLog() | ||||
|             OperResult data = new(); | ||||
|             var tag = _globalDeviceData.AllVariables.FirstOrDefault(it => it.Name == item.Key); | ||||
|             if (tag == null) | ||||
|                 results.Add(item.Key, new("不存在变量:" + item.Key)); | ||||
|             if (tag.ProtectTypeEnum == ProtectTypeEnum.ReadOnly) | ||||
|                 results.Add(item.Key, new("只读变量:" + item.Key)); | ||||
|             if (!tag.RpcWriteEnable && !isBlazor) | ||||
|                 results.Add(item.Key, new("不允许远程写入:" + item.Key)); | ||||
|  | ||||
|             if (tag.IsMemoryVariable == true) | ||||
|             { | ||||
|                 results.Add(item.Key, tag.SetValue(item.Value)); | ||||
|             } | ||||
|             var dev = _collectDeviceHostService.CollectDeviceCores.FirstOrDefault(it => it.Device.Id == tag.DeviceId); | ||||
|             if (dev == null) | ||||
|                 results.Add(item.Key, new OperResult("系统错误,不存在对应采集设备,请稍候重试")); | ||||
|             if (dev.Device.DeviceStatus == DeviceStatusEnum.OffLine) | ||||
|                 results.Add(item.Key, new OperResult("设备已离线")); | ||||
|             if (dev.Device.DeviceStatus == DeviceStatusEnum.Pause) | ||||
|                 results.Add(item.Key, new OperResult("设备已暂停")); | ||||
|  | ||||
|             if (!results.ContainsKey(item.Key)) | ||||
|             { | ||||
|                 if (string.IsNullOrEmpty(tag.OtherMethod)) | ||||
|                 { | ||||
|                     LogTime = SysDateTimeExtensions.CurrentDateTime, | ||||
|                     OperateMessage = data.Exception, | ||||
|                     IsSuccess = data.IsSuccess, | ||||
|                     OperateMethod = WriteVariable, | ||||
|                     OperateObject = tag.Name, | ||||
|                     OperateSource = sourceDes, | ||||
|                     ParamJson = item.Value, | ||||
|                     ResultJson = data.Message | ||||
|                     //写入变量 | ||||
|                     JToken tagValue; | ||||
|                     try | ||||
|                     { | ||||
|                         tagValue = JToken.Parse(item.Value); | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         tagValue = JToken.Parse("\"" + item.Value + "\""); | ||||
|                     } | ||||
|                     if (WriteVariables.ContainsKey(dev)) | ||||
|                     { | ||||
|  | ||||
|                         WriteVariables[dev].Add(tag, tagValue); | ||||
|  | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         WriteVariables.Add(dev, new()); | ||||
|                         WriteVariables[dev].Add(tag, tagValue); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (WriteMethods.ContainsKey(dev)) | ||||
|                     { | ||||
|  | ||||
|                         WriteMethods[dev].Add(tag, item.Value); | ||||
|  | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         WriteVariables.Add(dev, new()); | ||||
|                         WriteVariables[dev].Add(tag, item.Value); | ||||
|                     } | ||||
|                 } | ||||
|                 ); | ||||
|             if (!data.IsSuccess) | ||||
|             { | ||||
|                 _logger.LogWarning($"写入变量[{tag.Name}]失败:{data.Message}"); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|  | ||||
|         foreach (var item in WriteVariables) | ||||
|         { | ||||
|             //执行变量附带的方法 | ||||
|             var method = dev.DeviceVariableMethodSources.FirstOrDefault(it => it.DeviceVariable == tag); | ||||
|             try | ||||
|             { | ||||
|                 data = await dev.InvokeMethodAsync(method, false, item.Value, token); | ||||
|                 var result = await item.Key.InVokeWriteAsync(item.Value, token); | ||||
|                 foreach (var resultItem in result) | ||||
|                 { | ||||
|                     string operObj; | ||||
|                     string parJson; | ||||
|                     if (resultItem.Key.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         operObj = items.Select(x => x.Key).ToJsonString(); | ||||
|                         parJson = items.Select(x => x.Value).ToJsonString(); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         operObj = resultItem.Key; | ||||
|                         parJson = items[resultItem.Key]; | ||||
|  | ||||
|                     } | ||||
|                     _logQueues.Enqueue( | ||||
|           new RpcLog() | ||||
|           { | ||||
|               LogTime = SysDateTimeExtensions.CurrentDateTime, | ||||
|               OperateMessage = resultItem.Value.Exception, | ||||
|               IsSuccess = resultItem.Value.IsSuccess, | ||||
|               OperateMethod = WriteVariable, | ||||
|               OperateObject = operObj, | ||||
|               OperateSource = sourceDes, | ||||
|               ParamJson = parJson, | ||||
|               ResultJson = resultItem.Value.Message | ||||
|           } | ||||
|           ); | ||||
|                     if (!resultItem.Value.IsSuccess) | ||||
|                     { | ||||
|                         _logger.LogWarning($"写入变量[{resultItem.Key}]失败:{resultItem.Value.Message}"); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 results.AddRange(result); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 data = new OperResult<string>(ex); | ||||
|             } | ||||
|             _logQueues.Enqueue( | ||||
| new RpcLog() | ||||
| { | ||||
|     LogTime = SysDateTimeExtensions.CurrentDateTime, | ||||
|     OperateMessage = data.Exception, | ||||
|     IsSuccess = data.IsSuccess, | ||||
|     OperateMethod = tag.OtherMethod, | ||||
|     OperateObject = tag.Name, | ||||
|     OperateSource = sourceDes, | ||||
|     ParamJson = item.Value?.ToString(), | ||||
|     ResultJson = data.Message | ||||
| } | ||||
| ); | ||||
|             if (!data.IsSuccess) | ||||
|             { | ||||
|                 _logger.LogWarning($"执行变量[{tag.Name}]方法[{tag.OtherMethod}]失败:{data.Message}"); | ||||
|                 _logger.LogWarning($"写入变量异常:{ex.Message + Environment.NewLine + ex.StackTrace}"); | ||||
|             } | ||||
|         } | ||||
|         return data; | ||||
|         foreach (var item in WriteMethods) | ||||
|         { | ||||
|             foreach (var writeMethod in item.Value) | ||||
|             { | ||||
|  | ||||
|                 //执行变量附带的方法 | ||||
|                 var method = item.Key.DeviceVariableMethodSources.FirstOrDefault(it => it.DeviceVariable == writeMethod.Key); | ||||
|                 OperResult<string> result; | ||||
|                 try | ||||
|                 { | ||||
|                     result = await item.Key.InvokeMethodAsync(method, false, writeMethod.Value, token); | ||||
|                     results.Add(writeMethod.Key.Name, result); | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     result = new OperResult<string>(ex); | ||||
|                     results.Add(writeMethod.Key.Name, result); | ||||
|                 } | ||||
|                 _logQueues.Enqueue( | ||||
|     new RpcLog() | ||||
|     { | ||||
|         LogTime = SysDateTimeExtensions.CurrentDateTime, | ||||
|         OperateMessage = result.Exception, | ||||
|         IsSuccess = result.IsSuccess, | ||||
|         OperateMethod = writeMethod.Key.OtherMethod, | ||||
|         OperateObject = writeMethod.Key.Name, | ||||
|         OperateSource = sourceDes, | ||||
|         ParamJson = writeMethod.Value?.ToString(), | ||||
|         ResultJson = result.Message | ||||
|     } | ||||
|     ); | ||||
|                 if (!result.IsSuccess) | ||||
|                 { | ||||
|                     _logger.LogWarning($"执行变量[{writeMethod.Key.Name}]方法[{writeMethod.Key.OtherMethod}]失败:{result.Message}"); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         return results; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     private async Task RpcLogInsertAsync() | ||||
|     { | ||||
|   | ||||
| @@ -319,6 +319,39 @@ | ||||
|       "UpdateUserId": null, | ||||
|       "SortCode": 0, | ||||
|       "ExtJson": null | ||||
|     }, | ||||
|  | ||||
|     { | ||||
|       "Id": 442505, | ||||
|       "FileName": "ThingsGateway.DLT645", | ||||
|       "AssembleName": "DLT645_2007", | ||||
|       "DriverTypeEnum": "Collect", | ||||
|       "FilePath": "Plugins/ThingsGateway.DLT645/ThingsGateway.DLT645.dll", | ||||
|       "CreateTime": "2023/8/6 18:22:33", | ||||
|       "CreateUser": "superAdmin", | ||||
|       "CreateUserId": 212725263002001, | ||||
|       "IsDelete": 0, | ||||
|       "UpdateTime": null, | ||||
|       "UpdateUser": null, | ||||
|       "UpdateUserId": null, | ||||
|       "SortCode": 0, | ||||
|       "ExtJson": null | ||||
|     }, | ||||
|     { | ||||
|       "Id": 442506, | ||||
|       "FileName": "ThingsGateway.DLT645", | ||||
|       "AssembleName": "DLT645_2007OverTcp", | ||||
|       "DriverTypeEnum": "Collect", | ||||
|       "FilePath": "Plugins/ThingsGateway.DLT645/ThingsGateway.DLT645.dll", | ||||
|       "CreateTime": "2023/8/6 18:22:33", | ||||
|       "CreateUser": "superAdmin", | ||||
|       "CreateUserId": 212725263002001, | ||||
|       "IsDelete": 0, | ||||
|       "UpdateTime": null, | ||||
|       "UpdateUser": null, | ||||
|       "UpdateUserId": null, | ||||
|       "SortCode": 0, | ||||
|       "ExtJson": null | ||||
|     } | ||||
|   ] | ||||
| } | ||||
| @@ -55,7 +55,7 @@ public interface IVariableService : ITransient | ||||
|     /// <summary> | ||||
|     /// 导出 | ||||
|     /// </summary> | ||||
|     Task<MemoryStream> ExportFileAsync(List<DeviceVariable> collectDeviceVariables = null); | ||||
|     Task<MemoryStream> ExportFileAsync(List<DeviceVariable> collectDeviceVariables = null, string deviceName = null); | ||||
|     /// <summary> | ||||
|     /// 导出 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -318,7 +318,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     [OperDesc("导出采集变量表", IsRecordPar = false)] | ||||
|     public async Task<MemoryStream> ExportFileAsync(List<DeviceVariable> deviceVariables = null) | ||||
|     public async Task<MemoryStream> ExportFileAsync(List<DeviceVariable> deviceVariables = null, string deviceName = null) | ||||
|     { | ||||
|         deviceVariables ??= await GetListAsync(a => !a.IsMemoryVariable); | ||||
|  | ||||
| @@ -343,7 +343,8 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|            ); | ||||
|        Dictionary<string, object> variableExport = new(); | ||||
|        //变量实体没有包含设备名称,手动插入 | ||||
|        variableExport.Add(ExportHelpers.DeviceName, collectDeviceDicts[devData.DeviceId].Name); | ||||
|        var devName = collectDeviceDicts.GetValueOrDefault(devData.DeviceId)?.Name ?? deviceName; | ||||
|        variableExport.Add(ExportHelpers.DeviceName, devName); | ||||
|  | ||||
|        foreach (var item in data) | ||||
|        { | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
| 		<PackageReference Include="Hardware.Info" Version="11.1.1.1" /> | ||||
| 		<PackageReference Include="CS-Script" Version="4.8.1" /> | ||||
| 		<!--CS-Script与Furion冲突,直接安装覆盖版本--> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.6.0" /> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.7.0" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
|   | ||||
| @@ -1855,6 +1855,11 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.CollectBase.PLC"> | ||||
|             <summary> | ||||
|             一般底层驱动,也有可能为null | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.CollectBase.ThingsGatewayBitConverter"> | ||||
|             <summary> | ||||
|             数据转换器 | ||||
| @@ -1906,9 +1911,9 @@ | ||||
|             采集驱动读取 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectBase.WriteValueAsync(ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken,System.Threading.CancellationToken)"> | ||||
|         <member name="M:ThingsGateway.Application.CollectBase.WriteValuesAsync(System.Collections.Generic.Dictionary{ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             写入变量值 | ||||
|             批量写入变量值,需返回变量名称/结果 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
| @@ -2242,12 +2247,12 @@ | ||||
|         <member name="M:ThingsGateway.Application.RpcSingletonService.#ctor(Microsoft.Extensions.Logging.ILogger{ThingsGateway.Application.RpcSingletonService})"> | ||||
|             <inheritdoc cref="T:ThingsGateway.Application.RpcSingletonService"/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.RpcSingletonService.InvokeDeviceMethodAsync(System.String,System.Collections.Generic.KeyValuePair{System.String,System.String},System.Boolean,System.Threading.CancellationToken)"> | ||||
|         <member name="M:ThingsGateway.Application.RpcSingletonService.InvokeDeviceMethodAsync(System.String,System.Collections.Generic.Dictionary{System.String,System.String},System.Boolean,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             反向RPC入口方法 | ||||
|             </summary> | ||||
|             <param name="sourceDes">触发该方法的源说明</param> | ||||
|             <param name="item">指定键为变量名称,值为附带方法参数或写入值</param> | ||||
|             <param name="items">指定键为变量名称,值为附带方法参数或写入值</param> | ||||
|             <param name="isBlazor">如果是true,不检查<see cref="P:ThingsGateway.Application.MemoryVariable.RpcWriteEnable"/>字段</param> | ||||
|             <param name="token"><see cref="T:System.Threading.CancellationToken"/> 取消源</param> | ||||
|             <returns></returns> | ||||
| @@ -3175,7 +3180,7 @@ | ||||
|             编辑变量 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.IVariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> | ||||
|         <member name="M:ThingsGateway.Application.IVariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable},System.String)"> | ||||
|             <summary> | ||||
|             导出 | ||||
|             </summary> | ||||
| @@ -3270,7 +3275,7 @@ | ||||
|         <member name="M:ThingsGateway.Application.VariableService.MemoryVariableExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.MemoryVariable})"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.VariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> | ||||
|         <member name="M:ThingsGateway.Application.VariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable},System.String)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.VariableService.MemoryVariablePreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)"> | ||||
| @@ -3505,7 +3510,7 @@ | ||||
|             执行特殊方法 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceCore.InVokeWriteAsync(ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken,System.Threading.CancellationToken)"> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceCore.InVokeWriteAsync(System.Collections.Generic.Dictionary{ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             执行变量写入 | ||||
|             </summary> | ||||
|   | ||||
| @@ -536,6 +536,7 @@ public class AlarmWorker : BackgroundService | ||||
|         HisAlarmTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"历史报警线程开始"); | ||||
|             await Task.Yield();//返回线程控制,不再阻塞 | ||||
|             try | ||||
|             { | ||||
|                 await Task.Delay(500, stoppingToken.Token); | ||||
| @@ -561,8 +562,14 @@ public class AlarmWorker : BackgroundService | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         { | ||||
|                             IsExited = true; | ||||
|                             return; | ||||
|                         } | ||||
|                         try | ||||
|                         { | ||||
|                             _logger.LogWarning("连接历史报警表失败,尝试初始化表"); | ||||
|                             sqlSugarClient.CodeFirst.InitTables(typeof(HistoryAlarm)); | ||||
|                             isSuccess = true; | ||||
|                             StatuString = OperResult.CreateSuccessResult(); | ||||
|   | ||||
| @@ -269,6 +269,7 @@ public class CollectDeviceCore | ||||
|         { | ||||
|             isInitSuccess = false; | ||||
|             GlobalDeviceData.CollectDevices.RemoveWhere(it => it.Id == Device.Id); | ||||
|             easyLock.SafeDispose(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -329,11 +330,6 @@ public class CollectDeviceCore | ||||
|                 return ThreadRunReturn.Continue; | ||||
|             } | ||||
|  | ||||
|             if (DeviceVariableSourceReads.Count == 0 && Device.DeviceVariableRunTimes.Where(a => string.IsNullOrEmpty(a.OtherMethod)).Any()) | ||||
|             { | ||||
|                 //无采集变量 | ||||
|                 return ThreadRunReturn.Continue; | ||||
|             } | ||||
|             if (token.IsCancellationRequested) | ||||
|                 return ThreadRunReturn.Break; | ||||
|  | ||||
| @@ -437,11 +433,11 @@ public class CollectDeviceCore | ||||
|                 if (_driver.IsConnected()) | ||||
|                 { | ||||
|                     //更新设备活动时间 | ||||
|                     Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, 0); | ||||
|                     Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, errorCount: 0); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, 999); | ||||
|                     Device.SetDeviceStatus(errorCount: 999); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -533,7 +529,7 @@ public class CollectDeviceCore | ||||
|  | ||||
|                         if (!string.IsNullOrEmpty(methodResult.MethodStr)) | ||||
|                         { | ||||
|                             string[] strs = methodResult.MethodStr?.Trim()?.Split(';'); | ||||
|                             string[] strs = methodResult.MethodStr?.Trim()?.TrimEnd(';').Split(';'); | ||||
|                             try | ||||
|                             { | ||||
|                                 int index = 0; | ||||
| @@ -545,6 +541,8 @@ public class CollectDeviceCore | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         if (strs.Length <= index) | ||||
|                                             continue; | ||||
|                                         //得到对于的方法参数值 | ||||
|                                         methodResult.MethodObj[i] = methodResult.Converter.ConvertFrom(strs[index], ps[i].ParameterType); | ||||
|                                         index++; | ||||
| @@ -600,8 +598,8 @@ public class CollectDeviceCore | ||||
|  | ||||
|                     if (!string.IsNullOrEmpty(deviceVariableMethodSource.MethodStr) || !string.IsNullOrEmpty(value)) | ||||
|                     { | ||||
|                         string[] strs1 = deviceVariableMethodSource.MethodStr?.Trim()?.Split(';'); | ||||
|                         string[] strs2 = value?.Trim()?.Split(';'); | ||||
|                         string[] strs1 = deviceVariableMethodSource.MethodStr?.Trim()?.TrimEnd(';').Split(';'); | ||||
|                         string[] strs2 = value?.Trim()?.TrimEnd(';').Split(';'); | ||||
|                         //通过分号分割,并且合并参数 | ||||
|                         var strs = strs1?.SpliceArray(strs2); | ||||
|                         int index = 0; | ||||
| @@ -667,18 +665,25 @@ public class CollectDeviceCore | ||||
|                     if (method.HasReturn && result != null && result.IsSuccess) | ||||
|                     { | ||||
|                         var content = deviceVariableMethodSource.Converter.ConvertTo(result.Content?.ToString()?.Replace($"\0", "")); | ||||
|                         var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(content); | ||||
|                         if (!operResult.IsSuccess) | ||||
|                         if (isRead) | ||||
|                         { | ||||
|                             _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(content); | ||||
|                             if (!operResult.IsSuccess) | ||||
|                             { | ||||
|                                 _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null); | ||||
|                         if (!operResult.IsSuccess) | ||||
|                         if (isRead) | ||||
|                         { | ||||
|                             _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null); | ||||
|                             if (!operResult.IsSuccess) | ||||
|                             { | ||||
|                                 _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     return result; | ||||
| @@ -707,46 +712,46 @@ public class CollectDeviceCore | ||||
|     /// 执行变量写入 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     internal async Task<OperResult> InVokeWriteAsync(DeviceVariableRunTime deviceVariable, JToken value, CancellationToken token) | ||||
|     internal async Task<Dictionary<string, OperResult>> InVokeWriteAsync(Dictionary<DeviceVariableRunTime, JToken> writeInfoLists, CancellationToken token) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await easyLock.WaitAsync(); | ||||
|             if (IsShareChannel) _driver.InitDataAdapter(); | ||||
|             Dictionary<string, OperResult> results = new(); | ||||
|             foreach (var deviceVariable in writeInfoLists.Keys) | ||||
|             { | ||||
|                 if (!string.IsNullOrEmpty(deviceVariable.WriteExpressions)) | ||||
|                 { | ||||
|                     var jToken = writeInfoLists[deviceVariable]; | ||||
|                     object rawdata; | ||||
|                     if (jToken is JValue jValue) | ||||
|                     { | ||||
|                         rawdata = jValue.Value; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         rawdata = jToken.ToString(); | ||||
|                     } | ||||
|                     object data; | ||||
|                     try | ||||
|                     { | ||||
|                         data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata); | ||||
|                         writeInfoLists[deviceVariable] = JToken.FromObject(data); | ||||
|                     } | ||||
|                     catch (Exception ex) | ||||
|                     { | ||||
|                         results.Add(deviceVariable.Name, new OperResult(deviceVariable.Name + " 转换写入表达式失败:" + ex.Message)); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             if (!string.IsNullOrEmpty(deviceVariable.WriteExpressions)) | ||||
|             { | ||||
|                 var jToken = value; | ||||
|                 object rawdata; | ||||
|                 if (jToken is JValue jValue) | ||||
|                 { | ||||
|                     rawdata = jValue.Value; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rawdata = jToken.ToString(); | ||||
|                 } | ||||
|                 object data; | ||||
|                 try | ||||
|                 { | ||||
|                     data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata); | ||||
|                     var result = await _driver.WriteValueAsync(deviceVariable, JToken.FromObject(data), token); | ||||
|                     return result; | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     return new OperResult(deviceVariable.Name + " 转换写入表达式失败:" + ex.Message); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var result = await _driver.WriteValueAsync(deviceVariable, value, token); | ||||
|                 return result; | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return (new OperResult(ex)); | ||||
|             var result = await _driver.WriteValuesAsync(writeInfoLists. | ||||
|                 Where(a => !results.Any(b => b.Key == a.Key.Name)). | ||||
|                ToDictionary(item => item.Key, item => item.Value), | ||||
|                 token); | ||||
|  | ||||
|             return result; | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
| @@ -754,6 +759,8 @@ public class CollectDeviceCore | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 执行轮询特殊方法,并设置变量值 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -62,6 +62,7 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|     public async ValueTask DisposeAsync() | ||||
|     { | ||||
|         await StopThreadAsync(); | ||||
|         easyLock.SafeDispose(); | ||||
|         CollectDeviceCores.Clear(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -167,7 +167,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|         HistoryValueTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"历史数据线程开始"); | ||||
|             IsExited = false; | ||||
|             await Task.Yield();//返回线程控制,不再阻塞 | ||||
|             try | ||||
|             { | ||||
|                 var result = await GetHisDbAsync(); | ||||
| @@ -191,8 +191,14 @@ public class HistoryValueWorker : BackgroundService | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         { | ||||
|                             IsExited = true; | ||||
|                             return; | ||||
|                         } | ||||
|                         try | ||||
|                         { | ||||
|                             _logger.LogWarning("连接历史数据表失败,尝试初始化表"); | ||||
|                             sqlSugarClient.CodeFirst.InitTables(typeof(HistoryValue)); | ||||
|                             LastIsSuccess = true; | ||||
|                             StatuString = OperResult.CreateSuccessResult(); | ||||
| @@ -204,6 +210,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                             _logger.LogWarning(ex, "连接历史数据库失败"); | ||||
|                         } | ||||
|                     } | ||||
|                     IsExited = false; | ||||
|  | ||||
|                     while (!stoppingToken.Token.IsCancellationRequested) | ||||
|                     { | ||||
| @@ -299,7 +306,6 @@ public class HistoryValueWorker : BackgroundService | ||||
|                             LastIsSuccess = false; | ||||
|                         } | ||||
|                     } | ||||
|                     IsExited = true; | ||||
|  | ||||
|                 } | ||||
|             } | ||||
| @@ -317,9 +323,11 @@ public class HistoryValueWorker : BackgroundService | ||||
|                 IsExited = true; | ||||
|                 _logger?.LogError(ex, $"历史数据循环异常"); | ||||
|             } | ||||
|             IsExited = true; | ||||
|         } | ||||
|  , TaskCreationOptions.LongRunning); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 重启 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -225,7 +225,13 @@ public class UploadDeviceCore | ||||
|         { | ||||
|             _logger?.LogError(ex, $"{Device.Name} 释放失败"); | ||||
|         } | ||||
|         isInitSuccess = false; | ||||
|         finally | ||||
|         { | ||||
|             isInitSuccess = false; | ||||
|             easyLock.SafeDispose(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -51,6 +51,7 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|     public async ValueTask DisposeAsync() | ||||
|     { | ||||
|         await StopThreadAsync(); | ||||
|         easyLock.SafeDispose(); | ||||
|         UploadDeviceCores.Clear(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -21,7 +21,7 @@ using ThingsGateway.Application; | ||||
|  | ||||
| namespace ThingsGateway.Blazor; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>excel | ||||
| /// 导入excel | ||||
| /// </summary> | ||||
| public partial class ImportExcel | ||||
| { | ||||
| @@ -33,21 +33,21 @@ public partial class ImportExcel | ||||
|  | ||||
|     bool isSaveImport; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 导入 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public Func<Dictionary<string, ImportPreviewOutputBase>, Task> Import { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>ʾ | ||||
|     /// 是否显示 | ||||
|     /// </summary> | ||||
|     public bool IsShowImport { get; set; } | ||||
|     /// <summary> | ||||
|     /// Ԥ<EFBFBD><EFBFBD> | ||||
|     /// 预览 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Preview { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 当前步数 | ||||
|     /// </summary> | ||||
|     public int Step { get; set; } | ||||
|  | ||||
| @@ -75,7 +75,7 @@ public partial class ImportExcel | ||||
|             StateHasChanged(); | ||||
|             await Import.Invoke(ImportPreviews); | ||||
|             _importFile = null; | ||||
|             await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|             await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -54,7 +54,7 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase | ||||
|     /// </summary> | ||||
|     public UdpSessionPage UdpSessionPage; | ||||
|     /// <summary> | ||||
|     /// ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>1-TCPCLIENT<EFBFBD><EFBFBD>2-<2D><><EFBFBD>ڣ<EFBFBD>3-UDP<EFBFBD><EFBFBD>4-TCPServer | ||||
|     /// 选择,1-TCPCLIENT,2-串口,3-UDP,4-TCPServer | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public ChannelEnum Channel { get; set; } | ||||
| @@ -65,12 +65,12 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase | ||||
|     public override ThingsGateway.Foundation.IReadWriteDevice Plc { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ģ<EFBFBD><EFBFBD> | ||||
|     /// 模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD> | ||||
|     /// 自定义模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment OtherContent { get; set; } | ||||
| @@ -100,7 +100,7 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase | ||||
|                 TcpServerPage.LogAction = LogOut; | ||||
|             if (UdpSessionPage != null) | ||||
|                 UdpSessionPage.LogAction = LogOut; | ||||
|             //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|             //载入配置 | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -127,7 +127,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|     /// 导入设备 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task DownDeviceExportAsync(CollectDevice data) | ||||
|     public async Task DeviceImportAsync(CollectDevice data) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -145,7 +145,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|     /// 导入变量 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task DownDeviceExportAsync(List<DeviceVariable> data) | ||||
|     public async Task DeviceVariableImportAsync(List<DeviceVariable> data) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -159,6 +159,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 导出 | ||||
|     /// </summary> | ||||
| @@ -187,6 +188,51 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|             isDownExport = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 导出到excel | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task DownDeviceExportAsync(CollectDevice data) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             using var memoryStream = await CollectDeviceService.ExportFileAsync(new List<CollectDevice>() { data }); | ||||
|             memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|             using var streamRef = new DotNetStreamReference(stream: memoryStream); | ||||
|             _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|             await _helper.InvokeVoidAsync("downloadFileFromStream", $"设备导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             isDownExport = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 导出到excel | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task DownDeviceVariableExportAsync(List<DeviceVariable> data, string devName) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             using var memoryStream = await VariableService.ExportFileAsync(data, devName); | ||||
|             memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|             using var streamRef = new DotNetStreamReference(stream: memoryStream); | ||||
|             _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|             await _helper.InvokeVoidAsync("downloadFileFromStream", $"变量导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             isDownExport = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public void LogOut(TouchSocket.Core.LogLevel logLevel, object source, string message, Exception exception) | ||||
|     { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -20,7 +20,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class SerialClientPage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -36,7 +36,7 @@ public partial class SerialClientPage | ||||
|         SerialClient.SafeDispose(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public SerialClient GetSerialClient() | ||||
| @@ -47,7 +47,7 @@ public partial class SerialClientPage | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetSerialProperty(serialProperty); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         SerialClient.Setup(config); | ||||
|         return SerialClient; | ||||
|     } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -23,7 +23,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class TcpClientPage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -33,7 +33,7 @@ public partial class TcpClientPage | ||||
|     /// </summary> | ||||
|     private string IP = "127.0.0.1"; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>˿<EFBFBD> | ||||
|     /// 端口 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public int Port { get; set; } = 502; | ||||
| @@ -73,7 +73,7 @@ public partial class TcpClientPage | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public TcpClientEx GetTcpClient() | ||||
| @@ -83,7 +83,7 @@ public partial class TcpClientPage | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)).SetBufferLength(300); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         TcpClientEx.Setup(config); | ||||
|         return TcpClientEx; | ||||
|     } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -19,7 +19,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class TcpServerPage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -62,7 +62,7 @@ public partial class TcpServerPage | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public TcpService GetTcpServer() | ||||
| @@ -73,7 +73,7 @@ public partial class TcpServerPage | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); | ||||
|         config.SetBufferLength(300); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         TcpServer.Setup(config); | ||||
|         return TcpServer; | ||||
|     } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -19,7 +19,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class UdpSessionPage : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -62,7 +62,7 @@ public partial class UdpSessionPage : IDisposable | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public UdpSession GetUdpSession() | ||||
| @@ -73,7 +73,7 @@ public partial class UdpSessionPage : IDisposable | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(ip + ":" + port)).SetBufferLength(300); | ||||
|         config.SetBindIPHost(new IPHost(0)); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         UdpSession.Setup(config); | ||||
|         return UdpSession; | ||||
|     } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -32,7 +32,7 @@ using ThingsGateway.Application; | ||||
| namespace ThingsGateway.Blazor; | ||||
|  | ||||
| /// <summary> | ||||
| /// <EFBFBD>豸״̬ҳ<EFBFBD><EFBFBD> | ||||
| /// 设备状态页面 | ||||
| /// </summary> | ||||
| public partial class DeviceStatusPage : IDisposable | ||||
| { | ||||
| @@ -110,7 +110,7 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?"); | ||||
|             if (confirm) | ||||
|             { | ||||
|                 isAllRestart = true; | ||||
| @@ -142,8 +142,8 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     } | ||||
|     async Task ConfigAsync(long devId, bool? isStart) | ||||
|     { | ||||
|         var str = isStart == true ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>ͣ"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"ȷ<EFBFBD><EFBFBD>{str}?"); | ||||
|         var str = isStart == true ? "启动" : "暂停"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"确定{str}?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             CollectDeviceHostService.ConfigDeviceThread(devId, isStart == true); | ||||
| @@ -167,19 +167,19 @@ public partial class DeviceStatusPage : IDisposable | ||||
|             memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|             using var streamRef = new DotNetStreamReference(stream: memoryStream); | ||||
|             Helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|             await Helper.InvokeVoidAsync("downloadFileFromStream", $"<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.txt", streamRef); | ||||
|             await Helper.InvokeVoidAsync("downloadFileFromStream", $"报文导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.txt", streamRef); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             isDownExport = false; | ||||
|         } | ||||
|     } | ||||
|     //ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     //去除单个采集重启 | ||||
|     //async Task RestartAsync(long devId) | ||||
|     //{ | ||||
|     //    try | ||||
|     //    { | ||||
|     //        var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); | ||||
|     //        var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?"); | ||||
|     //        if (confirm) | ||||
|     //        { | ||||
|     //            isRestart = true; | ||||
| @@ -231,8 +231,8 @@ public partial class DeviceStatusPage : IDisposable | ||||
|  | ||||
|     async Task UpConfigAsync(long devId, bool? isStart) | ||||
|     { | ||||
|         var str = isStart == true ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>ͣ"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"ȷ<EFBFBD><EFBFBD>{str}?"); | ||||
|         var str = isStart == true ? "启动" : "暂停"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"确定{str}?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             UploadDeviceHostService.ConfigDeviceThread(devId, isStart == true); | ||||
| @@ -253,7 +253,7 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?"); | ||||
|             if (confirm) | ||||
|             { | ||||
|                 isRestart = true; | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -28,7 +28,7 @@ using ThingsGateway.Application; | ||||
|  | ||||
| namespace ThingsGateway.Blazor; | ||||
| /// <summary> | ||||
| /// ʵʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ | ||||
| /// 实时数据页 | ||||
| /// </summary> | ||||
| public partial class DeviceVariableRunTimePage | ||||
| { | ||||
| @@ -37,13 +37,13 @@ public partial class DeviceVariableRunTimePage | ||||
|     List<DeviceTree> _deviceGroups = new(); | ||||
|     string _searchName; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 设备名称 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     [SupplyParameterFromQuery] | ||||
|     public string DeviceName { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>ϴ<EFBFBD><EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 上传设备名称 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     [SupplyParameterFromQuery] | ||||
| @@ -149,15 +149,23 @@ public partial class DeviceVariableRunTimePage | ||||
|     private EventCallback<string> WriteValueAsync; | ||||
|     private async Task OnWriteValueAsync(DeviceVariableRunTime tag, string value) | ||||
|     { | ||||
|         var data = await RpcCore?.InvokeDeviceMethodAsync($"BLAZOR-{UserResoures.CurrentUser.Account}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", new KeyValuePair<string, string>(tag.Name, value), true); | ||||
|         if (!data.IsSuccess) | ||||
|         var data = await RpcCore?.InvokeDeviceMethodAsync($"BLAZOR-{UserResoures.CurrentUser.Account}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", | ||||
|  | ||||
|             new Dictionary<string, string>() | ||||
|             { | ||||
|  | ||||
|                 { tag.Name, value} | ||||
|             } | ||||
|  | ||||
|             , true); | ||||
|         if (data.Count > 0 && !data.FirstOrDefault().Value.IsSuccess) | ||||
|         { | ||||
|             throw new(data.Message); | ||||
|             throw new(data.FirstOrDefault().Value.Message); | ||||
|         } | ||||
|     } | ||||
|     private async Task WriteAsync(DeviceVariableRunTime collectVariableRunTime) | ||||
|     { | ||||
|         // <EFBFBD><EFBFBD><EFBFBD>첽<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD> | ||||
|         // 将异步方法添加到事件回调上 | ||||
|         WriteValueAsync = EventCallback.Factory.Create<string>(this, value => OnWriteValueAsync(collectVariableRunTime, value)); | ||||
|         await PopupService.OpenAsync(typeof(WriteValue), new Dictionary<string, object>() | ||||
|         { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -19,7 +19,7 @@ using ThingsGateway.Application; | ||||
| namespace ThingsGateway.Blazor; | ||||
|  | ||||
| /// <summary> | ||||
| /// Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣҳ<EFBFBD><EFBFBD> | ||||
| /// 硬件信息页面 | ||||
| /// </summary> | ||||
| public partial class HardwareInfoPage | ||||
| { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -25,7 +25,7 @@ using ThingsGateway.Application; | ||||
| namespace ThingsGateway.Blazor; | ||||
|  | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD>ʷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><EFBFBD> | ||||
| /// 历史报警页面 | ||||
| /// </summary> | ||||
| public partial class HistoryAlarmPage | ||||
| { | ||||
| @@ -75,7 +75,7 @@ public partial class HistoryAlarmPage | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("<EFBFBD><EFBFBD>ѯʧ<EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>" + ex.Message, AlertTypes.Warning)); | ||||
|                     await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("查询失败,请检查网络连接:" + ex.Message, AlertTypes.Warning)); | ||||
|                     return new() | ||||
|                     { | ||||
|                         Current = 1, | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -23,7 +23,7 @@ using ThingsGateway.Application; | ||||
|  | ||||
| namespace ThingsGateway.Blazor; | ||||
| /// <summary> | ||||
| /// ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><EFBFBD> | ||||
| /// 时序库页面 | ||||
| /// </summary> | ||||
| public partial class HistoryValuePage | ||||
| { | ||||
| @@ -74,7 +74,7 @@ public partial class HistoryValuePage | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("<EFBFBD><EFBFBD>ѯʧ<EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>" + ex.Message, AlertTypes.Warning)); | ||||
|                 await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("查询失败,请检查网络连接:" + ex.Message, AlertTypes.Warning)); | ||||
|                 return new() | ||||
|                 { | ||||
|                     Current = 1, | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD>룩<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD>鼰<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> | ||||
| //  GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -22,7 +22,7 @@ using ThingsGateway.Application; | ||||
|  | ||||
| namespace ThingsGateway.Blazor; | ||||
| /// <summary> | ||||
| /// ʵʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| /// 实时报警 | ||||
| /// </summary> | ||||
| public partial class RealAlarmPage | ||||
| { | ||||
|   | ||||
| @@ -428,13 +428,13 @@ | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.WriteAsync"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(ThingsGateway.Application.CollectDevice)"> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DeviceImportAsync(ThingsGateway.Application.CollectDevice)"> | ||||
|             <summary> | ||||
|             导入设备 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DeviceVariableImportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> | ||||
|             <summary> | ||||
|             导入变量 | ||||
|             </summary> | ||||
| @@ -447,6 +447,18 @@ | ||||
|             <param name="values"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(ThingsGateway.Application.CollectDevice)"> | ||||
|             <summary> | ||||
|             导出到excel | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceVariableExportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable},System.String)"> | ||||
|             <summary> | ||||
|             导出到excel | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.LogOut(TouchSocket.Core.LogLevel,System.Object,System.String,System.Exception)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|   | ||||
| @@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation; | ||||
| /// <summary> | ||||
| /// 自增 | ||||
| /// </summary> | ||||
| public sealed class EasyIncrementCount : DisposableObject | ||||
| public sealed class EasyIncrementCount : IDisposable | ||||
| { | ||||
|     private long current = 0; | ||||
|     private readonly EasyLock easyLock; | ||||
| @@ -30,6 +30,11 @@ public sealed class EasyIncrementCount : DisposableObject | ||||
|         IncreaseTick = tick; | ||||
|         easyLock = new EasyLock(); | ||||
|     } | ||||
|     /// <inheritdoc cref="EasyIncrementCount"/> | ||||
|     ~EasyIncrementCount() | ||||
|     { | ||||
|         easyLock.SafeDispose(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Tick | ||||
| @@ -117,10 +122,10 @@ public sealed class EasyIncrementCount : DisposableObject | ||||
|         } | ||||
|         easyLock.Release(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void Dispose(bool disposing) | ||||
|     public void Dispose() | ||||
|     { | ||||
|         easyLock.SafeDispose(); | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
| } | ||||
| @@ -15,11 +15,15 @@ namespace ThingsGateway.Foundation; | ||||
| /// <summary> | ||||
| /// EasyLock,使用轻量级SemaphoreSlim锁,只允许一个并发量,并记录并发信息 | ||||
| /// </summary> | ||||
| public sealed class EasyLock : DisposableObject | ||||
| public sealed class EasyLock : IDisposable | ||||
| { | ||||
|     private static long lockWaitCount; | ||||
|     private readonly Lazy<SemaphoreSlim> m_waiterLock = new(() => new SemaphoreSlim(1)); | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     ~EasyLock() | ||||
|     { | ||||
|         m_waiterLock.Value.SafeDispose(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 当前正在等待的数量 | ||||
|     /// </summary> | ||||
| @@ -28,6 +32,13 @@ public sealed class EasyLock : DisposableObject | ||||
|     /// 当前锁是否在等待当中 | ||||
|     /// </summary> | ||||
|     public bool IsWaitting => m_waiterLock.Value.CurrentCount == 0; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public void Dispose() | ||||
|     { | ||||
|         m_waiterLock.Value.SafeDispose(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 离开锁 | ||||
|     /// </summary> | ||||
| @@ -73,10 +84,5 @@ public sealed class EasyLock : DisposableObject | ||||
|         await m_waiterLock.Value.WaitAsync(timeSpan, token); | ||||
|         Interlocked.Decrement(ref lockWaitCount); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     protected override void Dispose(bool disposing) | ||||
|     { | ||||
|         m_waiterLock.Value.SafeDispose(); | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -29,7 +29,6 @@ using System.Runtime.InteropServices; | ||||
| using ThingsGateway.Foundation; | ||||
|  | ||||
| using TouchSocket.Resources; | ||||
| using TouchSocket.Sockets; | ||||
|  | ||||
| namespace ThingsGateway.Foundation; | ||||
|  | ||||
| @@ -326,27 +325,33 @@ public class TcpClientBaseEx : BaseSocket, ITcpClient | ||||
|     /// <param name="disposing"></param> | ||||
|     protected override void Dispose(bool disposing) | ||||
|     { | ||||
|         try | ||||
|         if (!DisposedValue) | ||||
|         { | ||||
|             privateEasyLock.Wait(); | ||||
|             if (this.m_online) | ||||
|             try | ||||
|             { | ||||
|                 this.m_online = false; | ||||
|                 this.MainSocket.TryClose(); | ||||
|                 this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); | ||||
|  | ||||
|                 this.MainSocket.SafeDispose(); | ||||
|                 this.m_delaySender.SafeDispose(); | ||||
|                 this.m_workStream.SafeDispose(); | ||||
|                 this.DataHandlingAdapter.SafeDispose(); | ||||
|                 this.PluginsManager.SafeDispose(); | ||||
|                 this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); | ||||
|                 privateEasyLock.Wait(); | ||||
|                 if (this.m_online) | ||||
|                 { | ||||
|                     this.m_online = false; | ||||
|                     this.MainSocket.TryClose(); | ||||
|                     this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); | ||||
|  | ||||
|                     this.MainSocket.SafeDispose(); | ||||
|                     this.m_delaySender.SafeDispose(); | ||||
|                     this.m_workStream.SafeDispose(); | ||||
|                     this.DataHandlingAdapter.SafeDispose(); | ||||
|                     this.PluginsManager.SafeDispose(); | ||||
|                     this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); | ||||
|                 } | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|                 privateEasyLock.Release(); | ||||
|             } | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             privateEasyLock.Release(); | ||||
|         } | ||||
|         privateEasyLock.SafeDispose(); | ||||
|  | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,7 @@ namespace ThingsGateway.Foundation; | ||||
| internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender | ||||
| { | ||||
|     private readonly Func<ResponsedData, bool> m_func; | ||||
|     private readonly SemaphoreSlim m_lock = new(1); | ||||
|     private readonly EasyLock easyLock = new(); | ||||
|     private readonly WaitData<ResponsedData> m_waitData = new WaitData<ResponsedData>(); | ||||
|     private readonly WaitDataAsync<ResponsedData> m_waitDataAsync = new WaitDataAsync<ResponsedData>(); | ||||
|  | ||||
| @@ -55,6 +55,7 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie | ||||
|         this.Client = default; | ||||
|         this.m_waitData.SafeDispose(); | ||||
|         this.m_waitDataAsync.SafeDispose(); | ||||
|         this.easyLock.SafeDispose(); | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|  | ||||
| @@ -121,7 +122,7 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             m_lock.Wait(); | ||||
|             easyLock.Wait(); | ||||
|             this.m_breaked = false; | ||||
|             this.Reset(); | ||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) | ||||
| @@ -184,7 +185,7 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             m_lock.Release(); | ||||
|             easyLock.Release(); | ||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) | ||||
|             { | ||||
|                 tcpClient.Disconnected -= this.OnDisconnected; | ||||
| @@ -224,7 +225,7 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await m_lock.WaitAsync(); | ||||
|             await easyLock.WaitAsync(); | ||||
|             this.m_breaked = false; | ||||
|             this.Reset(); | ||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) | ||||
| @@ -287,7 +288,7 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             m_lock.Release(); | ||||
|             easyLock.Release(); | ||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) | ||||
|             { | ||||
|                 tcpClient.Disconnected -= this.OnDisconnected; | ||||
|   | ||||
| @@ -46,19 +46,6 @@ public static class StringExtensions | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 将16进制的字符转换为int32。 | ||||
|     /// </summary> | ||||
|     /// <param name="hexString"></param> | ||||
|     /// <returns></returns> | ||||
|     public static int ByHexStringToInt32(this string hexString) | ||||
|     { | ||||
|         if (string.IsNullOrEmpty(hexString)) | ||||
|         { | ||||
|             return default; | ||||
|         } | ||||
|         return int.Parse(hexString, System.Globalization.NumberStyles.HexNumber); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc cref="Path.Combine(string[])"/> | ||||
|     /// 并把\\转为/ | ||||
|   | ||||
| @@ -15,6 +15,17 @@ namespace ThingsGateway.Foundation.Extension; | ||||
| /// <inheritdoc/> | ||||
| public static class OperResultExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 复制信息,包含第一个泛型类 | ||||
|     /// </summary> | ||||
|     public static OperResult<T1> Copy<T1, T2>(this OperResult<T1, T2> result) | ||||
|     { | ||||
|         OperResult<T1> result1 = new(result.ResultCode, result.Message) | ||||
|         { | ||||
|             Content = result.Content1 | ||||
|         }; | ||||
|         return result1; | ||||
|     } | ||||
|     #region Public Methods | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -13,7 +13,6 @@ | ||||
| using System.IO.Ports; | ||||
|  | ||||
| using TouchSocket.Resources; | ||||
| using TouchSocket.Sockets; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Serial; | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks> | ||||
| 		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks> | ||||
| 		<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments> | ||||
| 		<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||||
| 		<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> | ||||
| @@ -13,7 +13,7 @@ | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> | ||||
| 		<PackageReference Include="TouchSocket" Version="2.0.0-beta.135" /> | ||||
| 		<PackageReference Include="TouchSocket" Version="2.0.0-beta.138" /> | ||||
| 	</ItemGroup> | ||||
| 	<ItemGroup Condition="'$(TargetFramework)'!='net45'"> | ||||
| 		<PackageReference Include="System.IO.Ports" Version="7.0.0" /> | ||||
|   | ||||
| @@ -588,6 +588,9 @@ | ||||
|         <member name="M:ThingsGateway.Foundation.EasyIncrementCount.#ctor(System.Int64,System.Int64,System.Int32)"> | ||||
|             <inheritdoc cref="T:ThingsGateway.Foundation.EasyIncrementCount"/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyIncrementCount.Finalize"> | ||||
|             <inheritdoc cref="T:ThingsGateway.Foundation.EasyIncrementCount"/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.EasyIncrementCount.IncreaseTick"> | ||||
|             <summary> | ||||
|             Tick | ||||
| @@ -623,7 +626,7 @@ | ||||
|             重置当前序号的初始值 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyIncrementCount.Dispose(System.Boolean)"> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyIncrementCount.Dispose"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.EasyLock"> | ||||
| @@ -631,6 +634,9 @@ | ||||
|             EasyLock,使用轻量级SemaphoreSlim锁,只允许一个并发量,并记录并发信息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyLock.Finalize"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.EasyLock.LockWaitCount"> | ||||
|             <summary> | ||||
|             当前正在等待的数量 | ||||
| @@ -641,6 +647,9 @@ | ||||
|             当前锁是否在等待当中 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyLock.Dispose"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyLock.Release"> | ||||
|             <summary> | ||||
|             离开锁 | ||||
| @@ -666,9 +675,6 @@ | ||||
|             进入锁 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.EasyLock.Dispose(System.Boolean)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.TcpClientEx"> | ||||
|             <summary> | ||||
|             简单TCP客户端 | ||||
| @@ -1283,13 +1289,6 @@ | ||||
|             <param name="value"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Extension.String.StringExtensions.ByHexStringToInt32(System.String)"> | ||||
|             <summary> | ||||
|             将16进制的字符转换为int32。 | ||||
|             </summary> | ||||
|             <param name="hexString"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Extension.String.StringExtensions.CombinePathOS(System.String,System.String[])"> | ||||
|             <summary> | ||||
|             <inheritdoc cref="M:System.IO.Path.Combine(System.String[])"/> | ||||
| @@ -1313,6 +1312,11 @@ | ||||
|         <member name="T:ThingsGateway.Foundation.Extension.OperResultExtensions"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Extension.OperResultExtensions.Copy``2(ThingsGateway.Foundation.OperResult{``0,``1})"> | ||||
|             <summary> | ||||
|             复制信息,包含第一个泛型类 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Extension.OperResultExtensions.Copy``1(ThingsGateway.Foundation.OperResult)"> | ||||
|             <summary> | ||||
|             复制信息,不包含泛型类 | ||||
|   | ||||
| @@ -31,11 +31,11 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     private DataFormat dataFormat; | ||||
|     /// <inheritdoc/> | ||||
|     [JsonIgnore] | ||||
|     public Encoding Encoding { get; set; } = Encoding.UTF8; | ||||
|     public virtual Encoding Encoding { get; set; } = Encoding.UTF8; | ||||
|     /// <inheritdoc/> | ||||
|     public BcdFormat? BcdFormat { get; set; } | ||||
|     public virtual BcdFormat? BcdFormat { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public int StringLength { get; set; } | ||||
|     public virtual int StringLength { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 构造函数 | ||||
| @@ -55,7 +55,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public DataFormat DataFormat | ||||
|     public virtual DataFormat DataFormat | ||||
|     { | ||||
|         get | ||||
|         { | ||||
| @@ -69,9 +69,9 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public EndianType EndianType => endianType; | ||||
|     public virtual EndianType EndianType => endianType; | ||||
|     /// <inheritdoc/> | ||||
|     public bool IsStringReverseByteWord { get; set; } | ||||
|     public virtual bool IsStringReverseByteWord { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public virtual IThingsGatewayBitConverter CreateByDateFormat(DataFormat dataFormat) | ||||
| @@ -86,7 +86,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return byteConverter; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(bool value) | ||||
|     public virtual byte[] GetBytes(bool value) | ||||
|     { | ||||
|         return GetBytes(new bool[1] | ||||
|         { | ||||
| @@ -95,13 +95,13 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(bool[] values) | ||||
|     public virtual byte[] GetBytes(bool[] values) | ||||
|     { | ||||
|         return values?.BoolArrayToByte(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(short value) | ||||
|     public virtual byte[] GetBytes(short value) | ||||
|     { | ||||
|         byte[] bytes = BitConverter.GetBytes(value); | ||||
|         if (!IsSameOfSet()) | ||||
| @@ -111,7 +111,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return bytes; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(short[] value) | ||||
|     public virtual byte[] GetBytes(short[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -123,7 +123,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(ushort value) | ||||
|     public virtual byte[] GetBytes(ushort value) | ||||
|     { | ||||
|         byte[] bytes = BitConverter.GetBytes(value); | ||||
|         if (!IsSameOfSet()) | ||||
| @@ -133,7 +133,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return bytes; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(ushort[] value) | ||||
|     public virtual byte[] GetBytes(ushort[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -144,12 +144,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(int value) | ||||
|     public virtual byte[] GetBytes(int value) | ||||
|     { | ||||
|         return ByteTransDataFormat4(BitConverter.GetBytes(value)); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(int[] value) | ||||
|     public virtual byte[] GetBytes(int[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -160,12 +160,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(uint value) | ||||
|     public virtual byte[] GetBytes(uint value) | ||||
|     { | ||||
|         return ByteTransDataFormat4(BitConverter.GetBytes(value)); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(uint[] value) | ||||
|     public virtual byte[] GetBytes(uint[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -176,12 +176,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(long value) | ||||
|     public virtual byte[] GetBytes(long value) | ||||
|     { | ||||
|         return ByteTransDataFormat8(BitConverter.GetBytes(value)); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(long[] value) | ||||
|     public virtual byte[] GetBytes(long[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -192,12 +192,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(ulong value) | ||||
|     public virtual byte[] GetBytes(ulong value) | ||||
|     { | ||||
|         return ByteTransDataFormat8(BitConverter.GetBytes(value)); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(ulong[] value) | ||||
|     public virtual byte[] GetBytes(ulong[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -208,12 +208,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(float value) | ||||
|     public virtual byte[] GetBytes(float value) | ||||
|     { | ||||
|         return ByteTransDataFormat4(BitConverter.GetBytes(value)); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(float[] value) | ||||
|     public virtual byte[] GetBytes(float[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -224,12 +224,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(double value) | ||||
|     public virtual byte[] GetBytes(double value) | ||||
|     { | ||||
|         return ByteTransDataFormat8(BitConverter.GetBytes(value)); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(double[] value) | ||||
|     public virtual byte[] GetBytes(double[] value) | ||||
|     { | ||||
|         byte[] numArray = new byte[value.Length * 2]; | ||||
|         for (int index = 0; index < value.Length; ++index) | ||||
| @@ -240,7 +240,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] GetBytes(string value) | ||||
|     public virtual byte[] GetBytes(string value) | ||||
|     { | ||||
|         if (value == null) | ||||
|         { | ||||
| @@ -280,7 +280,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public bool IsSameOfSet() | ||||
|     public virtual bool IsSameOfSet() | ||||
|     { | ||||
|         return !(BitConverter.IsLittleEndian ^ (endianType == EndianType.Little)); | ||||
|     } | ||||
| @@ -288,7 +288,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public bool ToBoolean(byte[] buffer, int offset) | ||||
|     public virtual bool ToBoolean(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = new byte[buffer.Length]; | ||||
|         Array.Copy(buffer, 0, bytes, 0, buffer.Length); | ||||
| @@ -296,7 +296,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public byte ToByte(byte[] buffer, int offset) | ||||
|     public virtual byte ToByte(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = new byte[1]; | ||||
|         Array.Copy(buffer, offset, bytes, 0, bytes.Length); | ||||
| @@ -304,7 +304,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public byte[] ToByte(byte[] buffer, int offset, int length) | ||||
|     public virtual byte[] ToByte(byte[] buffer, int offset, int length) | ||||
|     { | ||||
|         byte[] bytes = new byte[length]; | ||||
|         Array.Copy(buffer, offset, bytes, 0, bytes.Length); | ||||
| @@ -317,7 +317,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     /// <param name="buffer"></param> | ||||
|     /// <param name="offset"></param> | ||||
|     /// <returns></returns> | ||||
|     public double ToDouble(byte[] buffer, int offset) | ||||
|     public virtual double ToDouble(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = ByteTransDataFormat8(buffer, offset); | ||||
|  | ||||
| @@ -325,7 +325,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public short ToInt16(byte[] buffer, int offset) | ||||
|     public virtual short ToInt16(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = new byte[2]; | ||||
|         Array.Copy(buffer, offset, bytes, 0, bytes.Length); | ||||
| @@ -337,7 +337,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public int ToInt32(byte[] buffer, int offset) | ||||
|     public virtual int ToInt32(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = ByteTransDataFormat4(buffer, offset); | ||||
|  | ||||
| @@ -345,14 +345,14 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public long ToInt64(byte[] buffer, int offset) | ||||
|     public virtual long ToInt64(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = ByteTransDataFormat8(buffer, offset); | ||||
|         return BitConverter.ToInt64(bytes, 0); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public float ToSingle(byte[] buffer, int offset) | ||||
|     public virtual float ToSingle(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = ByteTransDataFormat4(buffer, offset); | ||||
|  | ||||
| @@ -360,13 +360,13 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public string ToString(byte[] buffer) | ||||
|     public virtual string ToString(byte[] buffer) | ||||
|     { | ||||
|         return ToString(buffer, 0, buffer.Length); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public string ToString(byte[] buffer, int offset, int length) | ||||
|     public virtual string ToString(byte[] buffer, int offset, int length) | ||||
|     { | ||||
|         byte[] numArray = buffer.SelectMiddle(offset, length); | ||||
|         if (BcdFormat != null) | ||||
| @@ -385,7 +385,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ushort ToUInt16(byte[] buffer, int offset) | ||||
|     public virtual ushort ToUInt16(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = new byte[2]; | ||||
|         Array.Copy(buffer, offset, bytes, 0, 2); | ||||
| @@ -397,7 +397,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public uint ToUInt32(byte[] buffer, int offset) | ||||
|     public virtual uint ToUInt32(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = ByteTransDataFormat4(buffer, offset); | ||||
|  | ||||
| @@ -405,7 +405,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ulong ToUInt64(byte[] buffer, int offset) | ||||
|     public virtual ulong ToUInt64(byte[] buffer, int offset) | ||||
|     { | ||||
|         byte[] bytes = ByteTransDataFormat8(buffer, offset); | ||||
|         return BitConverter.ToUInt64(bytes, 0); | ||||
| @@ -508,7 +508,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public bool[] ToBoolean(byte[] buffer, int offset, int len) | ||||
|     public virtual bool[] ToBoolean(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         bool[] flagArray = new bool[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -519,7 +519,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public double[] ToDouble(byte[] buffer, int offset, int len) | ||||
|     public virtual double[] ToDouble(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         double[] numArray = new double[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -530,7 +530,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public short[] ToInt16(byte[] buffer, int offset, int len) | ||||
|     public virtual short[] ToInt16(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         short[] numArray = new short[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -541,7 +541,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public int[] ToInt32(byte[] buffer, int offset, int len) | ||||
|     public virtual int[] ToInt32(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         int[] numArray = new int[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -552,7 +552,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public long[] ToInt64(byte[] buffer, int offset, int len) | ||||
|     public virtual long[] ToInt64(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         long[] numArray = new long[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -562,7 +562,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|         return numArray; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public float[] ToSingle(byte[] buffer, int offset, int len) | ||||
|     public virtual float[] ToSingle(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         float[] numArray = new float[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -573,7 +573,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ushort[] ToUInt16(byte[] buffer, int offset, int len) | ||||
|     public virtual ushort[] ToUInt16(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         ushort[] numArray = new ushort[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -584,7 +584,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public uint[] ToUInt32(byte[] buffer, int offset, int len) | ||||
|     public virtual uint[] ToUInt32(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         uint[] numArray = new uint[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
| @@ -595,7 +595,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ulong[] ToUInt64(byte[] buffer, int offset, int len) | ||||
|     public virtual ulong[] ToUInt64(byte[] buffer, int offset, int len) | ||||
|     { | ||||
|         ulong[] numArray = new ulong[len]; | ||||
|         for (int index = 0; index < len; ++index) | ||||
|   | ||||
| @@ -0,0 +1,14 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<OutputType>Exe</OutputType> | ||||
| 		<TargetFramework>net6.0</TargetFramework> | ||||
| 		<ImplicitUsings>enable</ImplicitUsings> | ||||
| 		<Nullable>enable</Nullable> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0"?> | ||||
| <doc> | ||||
|     <assembly> | ||||
|         <name>ModbusDemo</name> | ||||
|         <name>DLT645Test</name> | ||||
|     </assembly> | ||||
|     <members> | ||||
|     </members> | ||||
| @@ -0,0 +1,112 @@ | ||||
| using ThingsGateway.Foundation; | ||||
| using ThingsGateway.Foundation.Adapter.DLT645; | ||||
| using ThingsGateway.Foundation.Extension.Byte; | ||||
| using ThingsGateway.Foundation.Serial; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
| using TouchSocket.Sockets; | ||||
|  | ||||
| namespace DLT645Test | ||||
| { | ||||
|     internal class Program | ||||
|     { | ||||
|         static async Task Main(string[] args) | ||||
|         { | ||||
|  | ||||
|             await DLT645_2007ClientAsync(); | ||||
|  | ||||
|             Console.ReadLine(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         private static async Task DLT645_2007ClientAsync() | ||||
|         { | ||||
|             //链路基础配置项 | ||||
|             var config = new TouchSocketConfig(); | ||||
|             config.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要 | ||||
|             .SetSerialProperty(new SerialProperty() //串口链路才需要 | ||||
|             { | ||||
|                 PortName = "COM1" | ||||
|             }).SetBufferLength(1024); | ||||
|  | ||||
|             var serialClient = new SerialClient();//链路对象 | ||||
|             serialClient.Setup(config); | ||||
|  | ||||
|             //创建协议对象,构造函数需要传入对应链路对象 | ||||
|  | ||||
|             DLT645_2007 dlt6452007 = new(serialClient)//传入链路 | ||||
|             { | ||||
|                 //协议配置 | ||||
|                 DataFormat = DataFormat.ABCD, | ||||
|                 FrameTime = 0, | ||||
|                 CacheTimeout = 1000, | ||||
|                 ConnectTimeOut = 3000, | ||||
|                 TimeOut = 3000, | ||||
|                 EnableFEHead = true, | ||||
|             }; | ||||
|  | ||||
|             #region 读写测试 | ||||
|             //测试读取写入 | ||||
|             Console.WriteLine("dlt6452007:" + dlt6452007.SerialClient.SerialProperty.ToJson()); | ||||
|             await TestAsync(dlt6452007); | ||||
|             #endregion | ||||
|  | ||||
|         } | ||||
|  | ||||
|         private static async Task TestAsync(DLT645_2007 plc) | ||||
|         { | ||||
|             //下面的方法对应PLC读写协议对象都是通用的 | ||||
|             //注意下面的方法都带有CancellationToken传播,一般是在最后一个参数,默认为None | ||||
|  | ||||
|  | ||||
|             //var bytes02010100Result = await plc.ReadAsync("03010100", 20); | ||||
|             ////返回带有是否成功等参数,实际数据在data.Content中 | ||||
|             //Console.WriteLine("bytes02010100Result:" + (bytes02010100Result.IsSuccess ? bytes02010100Result.Content.ToHexString() : bytes02010100Result.Message)); | ||||
|             //Console.WriteLine("bytes02010100Result:" + (bytes02010100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToDouble(bytes02010100Result.Content, 0) : bytes02010100Result.Message)); | ||||
|  | ||||
|             //var bytes02020100Result = await plc.ReadAsync("02020100", 20); | ||||
|             ////返回带有是否成功等参数,实际数据在data.Content中 | ||||
|             //Console.WriteLine("bytes02020100Result:" + (bytes02020100Result.IsSuccess ? bytes02020100Result.Content.ToHexString() : bytes02020100Result.Message)); | ||||
|             //Console.WriteLine("bytes02020100Result:" + (bytes02020100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToDouble(bytes02020100Result.Content, 0) : bytes02020100Result.Message)); | ||||
|  | ||||
|             //var bytes02020100Result = await plc.ReadAsync("04000103", 1); | ||||
|             ////返回带有是否成功等参数,实际数据在data.Content中 | ||||
|             //Console.WriteLine("bytes02020100Result:" + (bytes02020100Result.IsSuccess ? bytes02020100Result.Content.ToHexString() : bytes02020100Result.Message)); | ||||
|             //Console.WriteLine("bytes02020100Result:" + (bytes02020100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToString(bytes02020100Result.Content) : bytes02020100Result.Message)); | ||||
|  | ||||
|  | ||||
|             var test1 = await plc.ReadDeviceStationAsync(); | ||||
|             Console.WriteLine("bytes02020100Result:" + (test1.IsSuccess ? test1.Content : test1.Message)); | ||||
|  | ||||
|             var test2 = await plc.WriteDeviceStationAsync("311111111114"); | ||||
|             Console.WriteLine("bytes02020100Result:" + (test2.IsSuccess ? test2.Message : test2.Message)); | ||||
|             plc.BroadcastTime(DateTime.Now); | ||||
|             plc.Station = "311111111114"; | ||||
|  | ||||
|             var test3 = await plc.WriteBaudRateAsync(19200); | ||||
|             Console.WriteLine("bytes02020100Result:" + (test3.IsSuccess ? test3.Message : test3.Message)); | ||||
|             var test4 = await plc.FreezeAsync(DateTime.Now); | ||||
|             Console.WriteLine("bytes02020100Result:" + (test4.IsSuccess ? test4.Message : test4.Message)); | ||||
|  | ||||
|             var test5 = await plc.WritePasswordAsync(1, "66666666", "11111111"); | ||||
|             Console.WriteLine("bytes02020100Result:" + (test5.IsSuccess ? test5.Message : test5.Message)); | ||||
|             plc.Password = "11111111"; | ||||
|  | ||||
|  | ||||
|  | ||||
|             var bytes02020100Result1 = await plc.ReadAsync("04000403", 1); | ||||
|             //返回带有是否成功等参数,实际数据在data.Content中 | ||||
|             Console.WriteLine("bytes02020100Result:" + (bytes02020100Result1.IsSuccess ? bytes02020100Result1.Content.ToHexString() : bytes02020100Result1.Message)); | ||||
|             Console.WriteLine("bytes02020100Result:" + (bytes02020100Result1.IsSuccess ? plc.ThingsGatewayBitConverter.ToString(bytes02020100Result1.Content) : bytes02020100Result1.Message)); | ||||
|  | ||||
|             var test = await plc.WriteAsync("04000403", "33"); | ||||
|             //返回带有是否成功等参数,实际数据在data.Content中 | ||||
|             Console.WriteLine("test:" + test.Message); | ||||
|             var bytes02020100Result = await plc.ReadAsync("04000403", 1); | ||||
|             //返回带有是否成功等参数,实际数据在data.Content中 | ||||
|             Console.WriteLine("bytes02020100Result:" + (bytes02020100Result.IsSuccess ? bytes02020100Result.Content.ToHexString() : bytes02020100Result.Message)); | ||||
|             Console.WriteLine("bytes02020100Result:" + (bytes02020100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToString(bytes02020100Result.Content) : bytes02020100Result.Message)); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<OutputType>Exe</OutputType> | ||||
| 		<TargetFramework>net6.0</TargetFramework> | ||||
| 		<ImplicitUsings>enable</ImplicitUsings> | ||||
| 		<Nullable>enable</Nullable> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0"?> | ||||
| <doc> | ||||
|     <assembly> | ||||
|         <name>OPCUAClientDemo</name> | ||||
|         <name>ModbusTest</name> | ||||
|     </assembly> | ||||
|     <members> | ||||
|     </members> | ||||
| @@ -12,7 +12,7 @@ namespace ModbusDemo | ||||
|     { | ||||
|         static async Task Main(string[] args) | ||||
|         { | ||||
|             //await ModbusClientAsync(); | ||||
|             await ModbusClientAsync(); | ||||
| 
 | ||||
|             await ModbusServerAsync(); | ||||
| 
 | ||||
| @@ -7,6 +7,7 @@ | ||||
|     <Nullable>enable</Nullable> | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" /> | ||||
|   </ItemGroup> | ||||
| @@ -0,0 +1,8 @@ | ||||
| <?xml version="1.0"?> | ||||
| <doc> | ||||
|     <assembly> | ||||
|         <name>OPCUAClientTest</name> | ||||
|     </assembly> | ||||
|     <members> | ||||
|     </members> | ||||
| </doc> | ||||
| @@ -19,7 +19,10 @@ namespace ModbusDemo | ||||
|             await oPCUAClient.ConnectAsync(); | ||||
| 
 | ||||
|             var testData1 = await oPCUAClient.ReadJTokenValueAsync(new[] { "ns=2;i=2897" }); | ||||
|             await oPCUAClient.WriteNodeAsync("ns=2;i=2897", testData1.FirstOrDefault().Item3); | ||||
|             await oPCUAClient.WriteNodeAsync(new() | ||||
|             { | ||||
|                 {"ns=2;i=2897", testData1.FirstOrDefault().Item3 } | ||||
|             }); | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| @@ -1,14 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <ImplicitUsings>enable</ImplicitUsings> | ||||
|     <Nullable>enable</Nullable> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -1,7 +1,7 @@ | ||||
| <Project> | ||||
| 	<PropertyGroup> | ||||
| 		<TargetFrameworks>net6.0;net7.0</TargetFrameworks> | ||||
| 		<Version>2.0.6.0</Version> | ||||
| 		<Version>2.1.0.0</Version> | ||||
| 		<Authors>Diego</Authors> | ||||
| 		<Product>ThingsGateway</Product> | ||||
| 		<Copyright>© 2023-present Diego</Copyright> | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,459 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using System.ComponentModel; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Byte; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
| using ThingsGateway.Foundation.Serial; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
| /// <summary> | ||||
| /// DLT645_2007 | ||||
| /// </summary> | ||||
| public class DLT645_2007 : ReadWriteDevicesSerialBase | ||||
| { | ||||
|  | ||||
|     /// <summary> | ||||
|     /// DLT645_2007 | ||||
|     /// </summary> | ||||
|     /// <param name="serialClient"></param> | ||||
|     public DLT645_2007(SerialClient serialClient) : base(serialClient) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 组包缓存时间/ms | ||||
|     /// </summary> | ||||
|     [Description("组包缓存时间ms")] | ||||
|     public int CacheTimeout { get; set; } = 1000; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 增加FE FE FE FE的报文头部 | ||||
|     /// </summary> | ||||
|     [Description("前导符报文头")] | ||||
|     public bool EnableFEHead { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 帧前时间ms | ||||
|     /// </summary> | ||||
|     [Description("帧前时间ms")] | ||||
|     public int FrameTime { get; set; } | ||||
|     /// <summary> | ||||
|     /// 写入需操作员代码 | ||||
|     /// </summary> | ||||
|     [Description("操作员代码")] | ||||
|     public string OperCode { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入密码 | ||||
|     /// </summary> | ||||
|     [Description("写入密码")] | ||||
|     public string Password { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 通讯地址BCD码,一般应该是12个字符 | ||||
|     /// </summary> | ||||
|     [Description("通讯地址")] | ||||
|     public string Station { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() => base.GetAddressDescription() + Environment.NewLine; | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, length, (byte)ControlCode.Read, Station); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 return (MessageBase)result.RequestInfo; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<byte[]>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter() | ||||
|     { | ||||
|         var dataHandleAdapter = new DLT645_2007DataHandleAdapter | ||||
|         { | ||||
|             EnableFEHead = EnableFEHead | ||||
|         }; | ||||
|         SerialClient.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken token = default) | ||||
|     { | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             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, 1, (byte)ControlCode.Write, Station, data, strArray); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 return (MessageBase)result.RequestInfo; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<byte[]>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <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, uint value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token); | ||||
|     /// <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/> | ||||
|     public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token); | ||||
|  | ||||
|  | ||||
|     #region 其他方法 | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 广播校时 | ||||
|     /// </summary> | ||||
|     /// <param name="dateTime"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public OperResult BroadcastTime(DateTime dateTime, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(token); | ||||
|             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()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 SerialClient.Send(commandResult.Content); | ||||
|                 return OperResult.CreateSuccessResult(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 冻结 | ||||
|     /// </summary> | ||||
|     /// <param name="dateTime"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}"; | ||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; | ||||
|             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()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|  | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 读取通信地址 | ||||
|     /// </summary> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     var buffer = result1.Content.SelectMiddle(0, 6).BytesAdd(-0x33); | ||||
|                     return OperResult.CreateSuccessResult(buffer.Reverse().ToArray().ToHexString()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 修改波特率 | ||||
|     /// </summary> | ||||
|     /// <param name="baudRate"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             byte baudRateByte; | ||||
|             switch (baudRate) | ||||
|             { | ||||
|                 case 600: baudRateByte = 0x02; break; | ||||
|                 case 1200: baudRateByte = 0x04; break; | ||||
|                 case 2400: baudRateByte = 0x08; break; | ||||
|                 case 4800: baudRateByte = 0x10; break; | ||||
|                 case 9600: baudRateByte = 0x20; break; | ||||
|                 case 19200: baudRateByte = 0x40; break; | ||||
|                 default: return new OperResult<string>($"不支持此波特率:{baudRate}"); | ||||
|             } | ||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; | ||||
|             if (Station.Length < 12) Station = Station.PadLeft(12, '0'); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 更新通信地址 | ||||
|     /// </summary> | ||||
|     /// <param name="station"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|  | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 修改密码 | ||||
|     /// </summary> | ||||
|     /// <param name="level"></param> | ||||
|     /// <param name="oldPassword"></param> | ||||
|     /// <param name="newPassword"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|  | ||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; | ||||
|             if (Station.Length < 12) Station = Station.PadLeft(12, '0'); | ||||
|             string str = $"04000C{level:D2}"; | ||||
|  | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword, | ||||
|                 str.ByHexStringToBytes().Reverse().ToArray() | ||||
|                 .SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray()) | ||||
|                 .SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray()) | ||||
|                 , Station.ByHexStringToBytes().Reverse().ToArray()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     #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, | ||||
| } | ||||
| @@ -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 System.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Byte; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
|  | ||||
| /// <summary> | ||||
| /// DLT645_2007Address | ||||
| /// </summary> | ||||
| public class DLT645_2007Address : DeviceAddressBase | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public DLT645_2007Address() | ||||
|     { | ||||
|  | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public DLT645_2007Address(string address, ushort len) | ||||
|     { | ||||
|         Parse(address, len); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public DLT645_2007Address(string address, byte[] station) | ||||
|     { | ||||
|         Station = station; | ||||
|         Parse(address, 0); | ||||
|     } | ||||
|  | ||||
|     /// <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]; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void Parse(string address, int length) | ||||
|     { | ||||
|         var result = ParseFrom(address, length); | ||||
|         if (result.IsSuccess) | ||||
|         { | ||||
|             Length = result.Content.Length; | ||||
|             AddressStart = result.Content.AddressStart; | ||||
|             DataId = result.Content.DataId; | ||||
|             Station = result.Content.Station; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             throw new Exception(result.Message); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     /// <param name="address"></param> | ||||
|     /// <param name="length"></param> | ||||
|     /// <returns></returns> | ||||
|     public static OperResult<DLT645_2007Address> ParseFrom(string address, int length) | ||||
|     { | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             DLT645_2007Address dLT645_2007Address = new(); | ||||
|             byte[] array; | ||||
|             array = new byte[0]; | ||||
|             dLT645_2007Address.Length = length; | ||||
|             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()) return new OperResult<DLT645_2007Address>("通讯地址不能为空"); | ||||
|                         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 OperResult.CreateSuccessResult(dLT645_2007Address); | ||||
|  | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<DLT645_2007Address>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <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(); | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,106 @@ | ||||
| #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.Byte; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
| /// <summary> | ||||
| /// DLT645_2007 | ||||
| /// </summary> | ||||
| public class DLT645_2007BitConverter : ThingsGatewayBitConverter | ||||
| { | ||||
|     /// <summary> | ||||
|     /// DLT645_2007 | ||||
|     /// </summary> | ||||
|     public DLT645_2007BitConverter(EndianType endianType) : base(endianType) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// DLT645协议转换double | ||||
|     /// </summary> | ||||
|     /// <param name="buffer">带数据项标识</param> | ||||
|     /// <param name="offset"></param> | ||||
|     /// <returns></returns> | ||||
|     public override double ToDouble(byte[] buffer, int offset) | ||||
|     { | ||||
|         return Convert.ToDouble(this.ToString(buffer, offset, buffer.Length)); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString(byte[] buffer) | ||||
|     { | ||||
|         return this.ToString(buffer, 0, buffer.Length); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString(byte[] buffer, int offset, int length) | ||||
|     { | ||||
|         buffer = buffer.SelectMiddle(offset, length); | ||||
|         buffer = buffer.BytesAdd(-0x33); | ||||
|         var dataInfos = DLT645Helper.GetDataInfos(buffer); | ||||
|         StringBuilder stringBuilder = new(); | ||||
|         foreach (var dataInfo in dataInfos) | ||||
|         { | ||||
|             //实际数据 | ||||
|             var content = buffer.SelectMiddle(4, dataInfo.ByteLength).Reverse().ToArray(); | ||||
|             if (dataInfo.IsSigned)//可能为负数 | ||||
|             { | ||||
|                 if (content[0] > 0x80)//最高位是表示正负 | ||||
|                 { | ||||
|                     content[0] = (byte)(content[0] - 0x80); | ||||
|                     if (dataInfo.Digtal == 0)//无小数点 | ||||
|                     { | ||||
|                         stringBuilder.AppendLine($"-{content.ToHexString()}"); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         stringBuilder.AppendLine((-(Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString()); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ToString(stringBuilder, dataInfo, content); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 ToString(stringBuilder, dataInfo, content); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return stringBuilder.ToString(); | ||||
|  | ||||
|         static void ToString(StringBuilder stringBuilder, DataInfo dataInfo, byte[] content) | ||||
|         { | ||||
|             if (dataInfo.Digtal < 0) | ||||
|             { | ||||
|                 stringBuilder.AppendLine($"{Encoding.ASCII.GetString(content)}"); | ||||
|             } | ||||
|             else if (dataInfo.Digtal == 0)//无小数点 | ||||
|             { | ||||
|                 stringBuilder.AppendLine($"{content.ToHexString()}"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 stringBuilder.AppendLine(((Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,115 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using System.ComponentModel; | ||||
|  | ||||
| using ThingsGateway.Foundation.Adapter.Modbus; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
|  | ||||
| /// <summary> | ||||
| /// DLT645_2007DataHandleAdapter | ||||
| /// </summary> | ||||
| public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<DLT645_2007Message> | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 增加FE FE FE FE的报文头部 | ||||
|     /// </summary> | ||||
|     [Description("前导符报文头")] | ||||
|     public bool EnableFEHead { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         //打包时加上4个FE字节 | ||||
|         if (EnableFEHead) | ||||
|         { | ||||
|             return DataTransUtil.SpliceArray(new byte[4] { 0xFE, 0xFE, 0xFE, 0xFE }, command); | ||||
|         } | ||||
|         return command; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override DLT645_2007Message GetInstance() | ||||
|     { | ||||
|         return new DLT645_2007Message(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(DLT645_2007Message request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         //因为设备可能带有FE前导符开头,这里找到0x68的位置 | ||||
|         int headCodeIndex = -1; | ||||
|         if (response != null) | ||||
|         { | ||||
|             for (int index = 0; index < response.Length; index++) | ||||
|             { | ||||
|                 if (response[index] == 0x68) | ||||
|                 { | ||||
|                     headCodeIndex = index; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         //帧起始符 地址域  帧起始符 控制码 数据域长度共10个字节 | ||||
|         if (headCodeIndex < 0 || headCodeIndex + 10 > response.Length) | ||||
|             return FilterResult.Cache; | ||||
|  | ||||
|  | ||||
|         var len = 10 + response[headCodeIndex + 9] + 2; | ||||
|  | ||||
|         if (response.Length - headCodeIndex < len) | ||||
|         { | ||||
|             return FilterResult.Cache; | ||||
|         } | ||||
|         if (response.Length - headCodeIndex >= len && response[len + headCodeIndex - 1] == 0x16) | ||||
|         { | ||||
|  | ||||
|             //检查校验码 | ||||
|             int sumCheck = 0; | ||||
|             for (int i = headCodeIndex; i < len + headCodeIndex - 2; i++) | ||||
|                 sumCheck += response[i]; | ||||
|             if ((byte)sumCheck != response[len + headCodeIndex - 2]) | ||||
|             { | ||||
|                 //校验错误 | ||||
|                 request.Message = "和校验错误"; | ||||
|                 request.ResultCode = ResultCode.Fail; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|             if ((response[headCodeIndex + 8] & 0x40) == 0x40)//控制码bit6为1时,返回错误 | ||||
|             { | ||||
|                 byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33); | ||||
|                 var error = DLT645Helper.Get2007ErrorMessage(byte1); | ||||
|                 request.Message = "异常控制码:" + $"0x{response[headCodeIndex + 8]:X2},错误信息:{error}"; | ||||
|                 request.ResultCode = ResultCode.Fail; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 request.Content = response.RemoveBegin(headCodeIndex + 10).RemoveLast(response.Length + 2 - len - headCodeIndex); | ||||
|                 request.ResultCode = ResultCode.Success; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             request.ResultCode = ResultCode.Error; | ||||
|             return FilterResult.Success; | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,34 @@ | ||||
| #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 DLT645_2007Message : MessageBase, IMessage | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public override int HeadBytesLength => -1; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override bool CheckHeadBytes(byte[] head) | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void SendBytesThen() | ||||
|     { | ||||
|         BodyLength = -1; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,416 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using System.ComponentModel; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Byte; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
| /// <summary> | ||||
| /// DLT645_2007 | ||||
| /// </summary> | ||||
| public class DLT645_2007OverTcp : ReadWriteDevicesTcpClientBase | ||||
| { | ||||
|  | ||||
|     /// <summary> | ||||
|     /// DLT645_2007 | ||||
|     /// </summary> | ||||
|     /// <param name="tcpClient"></param> | ||||
|     public DLT645_2007OverTcp(TcpClientEx tcpClient) : base(tcpClient) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 组包缓存时间/ms | ||||
|     /// </summary> | ||||
|     [Description("组包缓存时间ms")] | ||||
|     public int CacheTimeout { get; set; } = 1000; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 增加FE FE FE FE的报文头部 | ||||
|     /// </summary> | ||||
|     [Description("前导符报文头")] | ||||
|     public bool EnableFEHead { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 帧前时间ms | ||||
|     /// </summary> | ||||
|     [Description("帧前时间ms")] | ||||
|     public int FrameTime { get; set; } | ||||
|     /// <summary> | ||||
|     /// 写入需操作员代码 | ||||
|     /// </summary> | ||||
|     [Description("操作员代码")] | ||||
|     public string OperCode { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入密码 | ||||
|     /// </summary> | ||||
|     [Description("写入密码")] | ||||
|     public string Password { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 通讯地址BCD码,一般应该是12个字符 | ||||
|     /// </summary> | ||||
|     [Description("通讯地址")] | ||||
|     public string Station { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() => base.GetAddressDescription() + Environment.NewLine; | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, length, (byte)ControlCode.Read, Station); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 return (MessageBase)result.RequestInfo; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<byte[]>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter() | ||||
|     { | ||||
|         var dataHandleAdapter = new DLT645_2007DataHandleAdapter | ||||
|         { | ||||
|             EnableFEHead = EnableFEHead | ||||
|         }; | ||||
|         TcpClientEx.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken token = default) | ||||
|     { | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             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, 1, (byte)ControlCode.Write, Station, data, strArray); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 return (MessageBase)result.RequestInfo; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<byte[]>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <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, uint value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token); | ||||
|     /// <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/> | ||||
|     public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token); | ||||
|  | ||||
|  | ||||
|     #region 其他方法 | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 广播校时 | ||||
|     /// </summary> | ||||
|     /// <param name="dateTime"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public OperResult BroadcastTime(DateTime dateTime, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(token); | ||||
|             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()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 TcpClientEx.Send(commandResult.Content); | ||||
|                 return OperResult.CreateSuccessResult(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 冻结 | ||||
|     /// </summary> | ||||
|     /// <param name="dateTime"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}"; | ||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; | ||||
|             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()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|  | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 读取通信地址 | ||||
|     /// </summary> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     var buffer = result1.Content.SelectMiddle(0, 6).BytesAdd(-0x33); | ||||
|                     return OperResult.CreateSuccessResult(buffer.Reverse().ToArray().ToHexString()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 修改波特率 | ||||
|     /// </summary> | ||||
|     /// <param name="baudRate"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             byte baudRateByte; | ||||
|             switch (baudRate) | ||||
|             { | ||||
|                 case 600: baudRateByte = 0x02; break; | ||||
|                 case 1200: baudRateByte = 0x04; break; | ||||
|                 case 2400: baudRateByte = 0x08; break; | ||||
|                 case 4800: baudRateByte = 0x10; break; | ||||
|                 case 9600: baudRateByte = 0x20; break; | ||||
|                 case 19200: baudRateByte = 0x40; break; | ||||
|                 default: return new OperResult<string>($"不支持此波特率:{baudRate}"); | ||||
|             } | ||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; | ||||
|             if (Station.Length < 12) Station = Station.PadLeft(12, '0'); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 更新通信地址 | ||||
|     /// </summary> | ||||
|     /// <param name="station"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|  | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 修改密码 | ||||
|     /// </summary> | ||||
|     /// <param name="level"></param> | ||||
|     /// <param name="oldPassword"></param> | ||||
|     /// <param name="newPassword"></param> | ||||
|     /// <param name="token"></param> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(token); | ||||
|  | ||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; | ||||
|             if (Station.Length < 12) Station = Station.PadLeft(12, '0'); | ||||
|             string str = $"04000C{level:D2}"; | ||||
|  | ||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword, | ||||
|                 str.ByHexStringToBytes().Reverse().ToArray() | ||||
|                 .SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray()) | ||||
|                 .SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray()) | ||||
|                 , Station.ByHexStringToBytes().Reverse().ToArray()); | ||||
|             if (commandResult.IsSuccess) | ||||
|             { | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token); | ||||
|                 var result1 = ((MessageBase)result.RequestInfo); | ||||
|                 if (result1.IsSuccess) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return OperResult.CreateFailedResult<string>(result1); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateFailedResult<string>(commandResult); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<string>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
| } | ||||
| @@ -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 TouchSocket.Core; | ||||
| global using TouchSocket.Sockets; | ||||
| @@ -0,0 +1,14 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> | ||||
| 		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks> | ||||
|  | ||||
| 	</PropertyGroup> | ||||
| 	 | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
| 	  <ProjectReference Include="..\..\..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -0,0 +1,462 @@ | ||||
| <?xml version="1.0"?> | ||||
| <doc> | ||||
|     <assembly> | ||||
|         <name>ThingsGateway.Foundation.Adapter.DLT645</name> | ||||
|     </assembly> | ||||
|     <members> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DataInfo"> | ||||
|             <summary> | ||||
|             解析参数 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.ByteLength"> | ||||
|             <summary> | ||||
|             解析长度 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.Digtal"> | ||||
|             <summary> | ||||
|             小数位 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.IsSigned"> | ||||
|             <summary> | ||||
|             有符号解析 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645Helper.GetDataInfos(System.Byte[])"> | ||||
|             <summary> | ||||
|             获取返回的解析信息 | ||||
|             </summary> | ||||
|             <param name="buffer"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645Helper.GetDLT645_2007Command(System.String,System.Int32,System.Byte,System.String,System.Byte[],System.String[])"> | ||||
|             <summary> | ||||
|             获取DLT645报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.#ctor(ThingsGateway.Foundation.Serial.SerialClient)"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|             <param name="serialClient"></param> | ||||
|         </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"> | ||||
|             <summary> | ||||
|             增加FE FE FE FE的报文头部 | ||||
|             </summary> | ||||
|         </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"> | ||||
|             <summary> | ||||
|             写入需操作员代码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.Password"> | ||||
|             <summary> | ||||
|             写入密码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.Station"> | ||||
|             <summary> | ||||
|             通讯地址BCD码,一般应该是12个字符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.SetDataAdapter"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.String,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Byte,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Double,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Single,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int64,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt64,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt16,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int16,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.BroadcastTime(System.DateTime,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             广播校时 | ||||
|             </summary> | ||||
|             <param name="dateTime"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.FreezeAsync(System.DateTime,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             冻结 | ||||
|             </summary> | ||||
|             <param name="dateTime"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadDeviceStationAsync(System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             读取通信地址 | ||||
|             </summary> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             修改波特率 | ||||
|             </summary> | ||||
|             <param name="baudRate"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             更新通信地址 | ||||
|             </summary> | ||||
|             <param name="station"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             修改密码 | ||||
|             </summary> | ||||
|             <param name="level"></param> | ||||
|             <param name="oldPassword"></param> | ||||
|             <param name="newPassword"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.ControlCode"> | ||||
|             <summary> | ||||
|             控制码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Read"> | ||||
|             <summary> | ||||
|             读数据 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.ReadSub"> | ||||
|             <summary> | ||||
|             读后续数据 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.ReadStation"> | ||||
|             <summary> | ||||
|             读站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Write"> | ||||
|             <summary> | ||||
|             写数据 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WriteStation"> | ||||
|             <summary> | ||||
|             写站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.BroadcastTime"> | ||||
|             <summary> | ||||
|             广播校时 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Freeze"> | ||||
|             <summary> | ||||
|             冻结 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WriteBaudRate"> | ||||
|             <summary> | ||||
|             更新波特率 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WritePassword"> | ||||
|             <summary> | ||||
|             更新密码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address"> | ||||
|             <summary> | ||||
|             DLT645_2007Address | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor(System.String,System.UInt16)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor(System.String,System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.DataId"> | ||||
|             <summary> | ||||
|             数据标识 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Reverse"> | ||||
|             <summary> | ||||
|             反转解析 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Station"> | ||||
|             <summary> | ||||
|             站号信息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Parse(System.String,System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.ParseFrom(System.String,System.Int32)"> | ||||
|             <summary> | ||||
|             解析地址 | ||||
|             </summary> | ||||
|             <param name="address"></param> | ||||
|             <param name="length"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.ToString"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.#ctor(TouchSocket.Core.EndianType)"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToDouble(System.Byte[],System.Int32)"> | ||||
|             <summary> | ||||
|             DLT645协议转换double | ||||
|             </summary> | ||||
|             <param name="buffer">带数据项标识</param> | ||||
|             <param name="offset"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[],System.Int32,System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter"> | ||||
|             <summary> | ||||
|             DLT645_2007DataHandleAdapter | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.EnableFEHead"> | ||||
|             <summary> | ||||
|             增加FE FE FE FE的报文头部 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message,System.Byte[],System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.#ctor(ThingsGateway.Foundation.TcpClientEx)"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|             <param name="tcpClient"></param> | ||||
|         </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"> | ||||
|             <summary> | ||||
|             增加FE FE FE FE的报文头部 | ||||
|             </summary> | ||||
|         </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"> | ||||
|             <summary> | ||||
|             写入需操作员代码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.Password"> | ||||
|             <summary> | ||||
|             写入密码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.Station"> | ||||
|             <summary> | ||||
|             通讯地址BCD码,一般应该是12个字符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.SetDataAdapter"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.String,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Byte,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Double,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Single,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int64,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt64,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt16,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int16,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.BroadcastTime(System.DateTime,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             广播校时 | ||||
|             </summary> | ||||
|             <param name="dateTime"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.FreezeAsync(System.DateTime,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             冻结 | ||||
|             </summary> | ||||
|             <param name="dateTime"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadDeviceStationAsync(System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             读取通信地址 | ||||
|             </summary> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             修改波特率 | ||||
|             </summary> | ||||
|             <param name="baudRate"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             更新通信地址 | ||||
|             </summary> | ||||
|             <param name="station"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             修改密码 | ||||
|             </summary> | ||||
|             <param name="level"></param> | ||||
|             <param name="oldPassword"></param> | ||||
|             <param name="newPassword"></param> | ||||
|             <param name="token"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.HeadBytesLength"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.CheckHeadBytes(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.SendBytesThen"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|     </members> | ||||
| </doc> | ||||
| @@ -60,45 +60,94 @@ public class ModbusAddress : DeviceAddressBase | ||||
|     /// <inheritdoc/> | ||||
|     public override void Parse(string address, int length) | ||||
|     { | ||||
|         Length = length; | ||||
|         if (address.IndexOf(';') < 0) | ||||
|         var result = ParseFrom(address, length); | ||||
|         if (result.IsSuccess) | ||||
|         { | ||||
|             Address(address); | ||||
|  | ||||
|             Length = result.Content.Length; | ||||
|             AddressStart = result.Content.AddressStart; | ||||
|             ReadFunction = result.Content.ReadFunction; | ||||
|             if (result.Content.Station > 0) | ||||
|                 Station = result.Content.Station; | ||||
|             WriteFunction = result.Content.WriteFunction; | ||||
|         } | ||||
|         else | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     /// <param name="address"></param> | ||||
|     /// <param name="length"></param> | ||||
|     /// <returns></returns> | ||||
|     public static OperResult<ModbusAddress> ParseFrom(string address, int length) | ||||
|     { | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             string[] strArray = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); | ||||
|             for (int index = 0; index < strArray.Length; ++index) | ||||
|             ModbusAddress modbusAddress = new() | ||||
|             { | ||||
|                 if (strArray[index].ToUpper().StartsWith("S=")) | ||||
|                 Length = length | ||||
|             }; | ||||
|             if (address.IndexOf(';') < 0) | ||||
|             { | ||||
|                 Address(address); | ||||
|  | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 string[] strArray = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); | ||||
|                 for (int index = 0; index < strArray.Length; ++index) | ||||
|                 { | ||||
|                     if (Convert.ToInt16(strArray[index].Substring(2)) > 0) | ||||
|                         Station = byte.Parse(strArray[index].Substring(2)); | ||||
|                 } | ||||
|                 else if (strArray[index].ToUpper().StartsWith("W=")) | ||||
|                 { | ||||
|                     if (Convert.ToInt16(strArray[index].Substring(2)) > 0) | ||||
|                         this.WriteFunction = byte.Parse(strArray[index].Substring(2)); | ||||
|                 } | ||||
|                 else if (!strArray[index].Contains("=")) | ||||
|                 { | ||||
|                     Address(strArray[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].Contains("=")) | ||||
|                     { | ||||
|                         Address(strArray[index]); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void Address(string address) | ||||
|             return OperResult.CreateSuccessResult(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.AddressStart = int.Parse(address.Substring(1)) - 1; | ||||
|             } | ||||
|  | ||||
|  | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             var readF = ushort.Parse(address.Substring(0, 1)); | ||||
|             if (readF > 4) | ||||
|                 throw new("功能码错误"); | ||||
|             GetFunction(readF); | ||||
|             AddressStart = int.Parse(address.Substring(1)) - 1; | ||||
|             return new OperResult<ModbusAddress>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString() | ||||
|     { | ||||
| @@ -115,24 +164,6 @@ public class ModbusAddress : DeviceAddressBase | ||||
|         return stringGeter.ToString(); | ||||
|     } | ||||
|  | ||||
|     private void GetFunction(ushort readF) | ||||
|     { | ||||
|         switch (readF) | ||||
|         { | ||||
|             case 0: | ||||
|                 ReadFunction = 1; | ||||
|                 break; | ||||
|             case 1: | ||||
|                 ReadFunction = 2; | ||||
|                 break; | ||||
|             case 3: | ||||
|                 ReadFunction = 4; | ||||
|                 break; | ||||
|             case 4: | ||||
|                 ReadFunction = 3; | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|     private string GetFunctionString(int readF) | ||||
|     { | ||||
|         return readF switch | ||||
|   | ||||
| @@ -16,290 +16,294 @@ using ThingsGateway.Foundation.Extension.Bool; | ||||
| using ThingsGateway.Foundation.Extension.Byte; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| internal class ModbusHelper | ||||
| { | ||||
|     internal class ModbusHelper | ||||
|     /// <summary> | ||||
|     /// 添加Crc16 | ||||
|     /// </summary> | ||||
|     internal static byte[] AddCrc(byte[] command) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 添加Crc16 | ||||
|         /// </summary> | ||||
|         internal static byte[] AddCrc(byte[] command) | ||||
|         { | ||||
|             return EasyCRC16.CRC16(command); | ||||
|         } | ||||
|         return EasyCRC16.CRC16(command); | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 添加ModbusTcp报文头 | ||||
|         /// </summary> | ||||
|         internal static byte[] AddModbusTcpHead(byte[] modbus, ushort id) | ||||
|         { | ||||
|             byte[] tcp = new byte[modbus.Length + 6]; | ||||
|             tcp[0] = BitConverter.GetBytes(id)[1]; | ||||
|             tcp[1] = BitConverter.GetBytes(id)[0]; | ||||
|             tcp[4] = BitConverter.GetBytes(modbus.Length)[1]; | ||||
|             tcp[5] = BitConverter.GetBytes(modbus.Length)[0]; | ||||
|             modbus.CopyTo(tcp, 6); | ||||
|             return tcp; | ||||
|         } | ||||
|     /// <summary> | ||||
|     /// 添加ModbusTcp报文头 | ||||
|     /// </summary> | ||||
|     internal static byte[] AddModbusTcpHead(byte[] modbus, ushort id) | ||||
|     { | ||||
|         byte[] tcp = new byte[modbus.Length + 6]; | ||||
|         tcp[0] = BitConverter.GetBytes(id)[1]; | ||||
|         tcp[1] = BitConverter.GetBytes(id)[0]; | ||||
|         tcp[4] = BitConverter.GetBytes(modbus.Length)[1]; | ||||
|         tcp[5] = BitConverter.GetBytes(modbus.Length)[0]; | ||||
|         modbus.CopyTo(tcp, 6); | ||||
|         return tcp; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// modbus地址格式说明 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         internal static string GetAddressDescription() | ||||
|     /// <summary> | ||||
|     /// modbus地址格式说明 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     internal static string GetAddressDescription() | ||||
|     { | ||||
|         StringBuilder stringBuilder = new(); | ||||
|         stringBuilder.AppendLine("Modbus寄存器"); | ||||
|         stringBuilder.AppendLine("线圈寄存器使用从 00001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("离散输入寄存器使用从 10001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("输入寄存器使用从 30001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("保持寄存器使用从 40001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("举例:"); | ||||
|         stringBuilder.AppendLine("40001=>保持寄存器第一个寄存器"); | ||||
|         stringBuilder.AppendLine("额外格式:"); | ||||
|         stringBuilder.AppendLine("设备站号 ,比如40001;s=2; ,代表设备地址为2的保持寄存器第一个寄存器"); | ||||
|         stringBuilder.AppendLine("写入功能码 ,比如40001;w=16; ,代表保持寄存器第一个寄存器,写入值时采用0x10功能码,而不是默认的0x06功能码"); | ||||
|         return stringBuilder.ToString(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 通过错误码来获取到对应的文本消息 | ||||
|     /// </summary> | ||||
|     internal static string GetDescriptionByErrorCode(byte code) | ||||
|     { | ||||
|         return code switch | ||||
|         { | ||||
|             StringBuilder stringBuilder = new(); | ||||
|             stringBuilder.AppendLine("Modbus寄存器"); | ||||
|             stringBuilder.AppendLine("线圈寄存器使用从 00001 开始的地址编号。"); | ||||
|             stringBuilder.AppendLine("离散输入寄存器使用从 10001 开始的地址编号。"); | ||||
|             stringBuilder.AppendLine("输入寄存器使用从 30001 开始的地址编号。"); | ||||
|             stringBuilder.AppendLine("保持寄存器使用从 40001 开始的地址编号。"); | ||||
|             stringBuilder.AppendLine("举例:"); | ||||
|             stringBuilder.AppendLine("40001=>保持寄存器第一个寄存器"); | ||||
|             stringBuilder.AppendLine("额外格式:"); | ||||
|             stringBuilder.AppendLine("设备站号 ,比如40001;s=2; ,代表设备地址为2的保持寄存器第一个寄存器"); | ||||
|             stringBuilder.AppendLine("写入功能码 ,比如40001;w=16; ,代表保持寄存器第一个寄存器,写入值时采用0x10功能码,而不是默认的0x06功能码"); | ||||
|             return stringBuilder.ToString(); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 通过错误码来获取到对应的文本消息 | ||||
|         /// </summary> | ||||
|         internal static string GetDescriptionByErrorCode(byte code) | ||||
|         { | ||||
|             return code switch | ||||
|             { | ||||
|                 1 => "不支持的功能码", | ||||
|                 2 => "读取寄存器越界", | ||||
|                 3 => "读取长度超限", | ||||
|                 4 => "读写异常", | ||||
|                 _ => "未知错误", | ||||
|             }; | ||||
|         } | ||||
|             1 => "不支持的功能码", | ||||
|             2 => "读取寄存器越界", | ||||
|             3 => "读取长度超限", | ||||
|             4 => "读写异常", | ||||
|             _ => "未知错误", | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取modbus数据区内容,返回数据需去除Crc和报文头,例如:01 03 02 00 01,发送数据需报文头 | ||||
|         /// </summary> | ||||
|         /// <param name="send">发送数据</param> | ||||
|         /// <param name="response">返回数据</param> | ||||
|         /// <returns></returns> | ||||
|         internal static OperResult<byte[]> GetModbusData(byte[] send, byte[] response) | ||||
|     /// <summary> | ||||
|     /// 获取modbus数据区内容,返回数据需去除Crc和报文头,例如:01 03 02 00 01,发送数据需报文头 | ||||
|     /// </summary> | ||||
|     /// <param name="send">发送数据</param> | ||||
|     /// <param name="response">返回数据</param> | ||||
|     /// <returns></returns> | ||||
|     internal static OperResult<byte[], FilterResult> GetModbusData(byte[] send, byte[] response) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (response[1] >= 0x80)//错误码 | ||||
|                     return new OperResult<byte[]>(GetDescriptionByErrorCode(response[2])); | ||||
|                 if (send.Length == 0) | ||||
|                 { | ||||
|                     var result = OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3)); | ||||
|                     result.Message = "接收数据正确,但主机并没有主动请求数据"; | ||||
|                     result.ResultCode = ResultCode.Canceled; | ||||
|                     return result; | ||||
|                 } | ||||
|                 if (send[0] != response[0]) | ||||
|                     return new OperResult<byte[]>(string.Format("站号不一致", send[0], response[0])); | ||||
|                 if (send[1] != response[1]) | ||||
|                     return new OperResult<byte[]>(response) { Message = "功能码不一致" }; | ||||
|                 if (response.Length > 3) | ||||
|                     return OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3)); | ||||
|                 else | ||||
|                     return new OperResult<byte[]>(response) { Message = "数据长度为0" }; | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex.Message); | ||||
|             } | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 去除Crc,返回modbus数据区 | ||||
|         /// </summary> | ||||
|         /// <param name="send"></param> | ||||
|         /// <param name="response"></param> | ||||
|         /// <param name="crcCheck"></param> | ||||
|         /// <returns></returns> | ||||
|         internal static OperResult<byte[]> GetModbusRtuData(byte[] send, byte[] response, bool crcCheck = true) | ||||
|         { | ||||
|             if (response.Length < 5) | ||||
|                 return new OperResult<byte[]>("数据长度不足" + response.ToHexString()); | ||||
|             if (crcCheck && !EasyCRC16.CheckCRC16(response)) | ||||
|                 return new OperResult<byte[]>("Crc校验失败" + DataTransUtil.ByteToHexString(response, ' ')); | ||||
|             return GetModbusData(send, response.RemoveLast(2)); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 获取读取报文 | ||||
|         /// </summary> | ||||
|         internal static OperResult<byte[]> GetReadModbusCommand(string address, int length, byte station) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 ModbusAddress mAddress = new(address, station); | ||||
|                 return GetReadModbusCommand(mAddress, length); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex.Message); | ||||
|             } | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 获取写入布尔量报文,根据地址识别功能码 | ||||
|         /// </summary> | ||||
|         internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool[] values, byte station) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 ModbusAddress mAddress = new(address, station); | ||||
|                 //功能码或实际长度 | ||||
|                 if (values?.Length > 1 || mAddress.WriteFunction == 15) | ||||
|                     return GetWriteBoolModbusCommand(mAddress, values, values.Length); | ||||
|                 else | ||||
|                     return GetWriteBoolModbusCommand(address, values[0], station); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex.Message); | ||||
|             } | ||||
|         } | ||||
|             if (response.Length < 3) | ||||
|                 return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取写入字报文,根据地址识别功能码 | ||||
|         /// </summary> | ||||
|         internal static OperResult<byte[]> GetWriteModbusCommand(string address, byte[] value, byte station) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 ModbusAddress mAddress = new(address, station); | ||||
|                 //功能码或实际长度 | ||||
|                 if (value?.Length > 2 || mAddress.WriteFunction == 16) | ||||
|                     return GetWriteModbusCommand(mAddress, value); | ||||
|                 else | ||||
|                     return GetWriteOneModbusCommand(mAddress, value); | ||||
|  | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             if (response[1] >= 0x80)//错误码 | ||||
|                 return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success }; | ||||
|             if ((response.Length < response[2] + 3)) | ||||
|                 return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|  | ||||
|             if (send.Length == 0) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex.Message); | ||||
|                 var result = OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success); | ||||
|                 result.Message = "接收数据正确,但主机并没有主动请求数据"; | ||||
|                 return result; | ||||
|             } | ||||
|             if (send[0] != response[0]) | ||||
|                 return new OperResult<byte[], FilterResult>(string.Format("站号不一致", send[0], response[0])) { Content2 = FilterResult.Success }; | ||||
|             if (send[1] != response[1]) | ||||
|                 return new OperResult<byte[], FilterResult>() { Message = "功能码不一致", Content2 = FilterResult.Success }; | ||||
|             return OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 获取读取报文 | ||||
|         /// </summary> | ||||
|         private static OperResult<byte[]> GetReadModbusCommand(ModbusAddress mAddress, int length) | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             byte[] array = new byte[6] | ||||
|             { | ||||
|             (byte) mAddress.Station, | ||||
|             (byte) mAddress.ReadFunction, | ||||
|             BitConverter.GetBytes(mAddress.AddressStart)[1], | ||||
|             BitConverter.GetBytes(mAddress.AddressStart)[0], | ||||
|             BitConverter.GetBytes(length)[1], | ||||
|             BitConverter.GetBytes(length)[0] | ||||
|             }; | ||||
|  | ||||
|             return OperResult.CreateSuccessResult(array); | ||||
|             return new OperResult<byte[], FilterResult>(ex.Message) { Content2 = FilterResult.Success }; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取05写入布尔量报文 | ||||
|         /// </summary> | ||||
|         private static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station) | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 去除Crc,返回modbus数据区 | ||||
|     /// </summary> | ||||
|     /// <param name="send"></param> | ||||
|     /// <param name="response"></param> | ||||
|     /// <param name="crcCheck"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static OperResult<byte[], FilterResult> GetModbusRtuData(byte[] send, byte[] response, bool crcCheck = true) | ||||
|     { | ||||
|         if (response.Length < 3) | ||||
|             return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|         var data = response.SelectMiddle(0, response[2] + 5); | ||||
|         if (crcCheck && !EasyCRC16.CheckCRC16(data)) | ||||
|             return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success }; | ||||
|         return GetModbusData(send, data.RemoveLast(2)); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取读取报文 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetReadModbusCommand(string address, int length, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (address.IndexOf('.') <= 0) | ||||
|                 { | ||||
|                     ModbusAddress mAddress = new(address, station); | ||||
|                     return GetWriteBoolModbusCommand(mAddress, value); | ||||
|                 } | ||||
|                 return new("不支持写入字寄存器的某一位"); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex.Message); | ||||
|             } | ||||
|             ModbusAddress mAddress = new(address, station); | ||||
|             return GetReadModbusCommand(mAddress, length); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取05写入布尔量报文 | ||||
|         /// </summary> | ||||
|         private static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value) | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取写入布尔量报文,根据地址识别功能码 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool[] values, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             ModbusAddress mAddress = new(address, station); | ||||
|             //功能码或实际长度 | ||||
|             if (values?.Length > 1 || mAddress.WriteFunction == 15) | ||||
|                 return GetWriteBoolModbusCommand(mAddress, values, values.Length); | ||||
|             else | ||||
|                 return GetWriteBoolModbusCommand(address, values[0], station); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取写入字报文,根据地址识别功能码 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetWriteModbusCommand(string address, byte[] value, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             ModbusAddress mAddress = new(address, station); | ||||
|             //功能码或实际长度 | ||||
|             if (value?.Length > 2 || mAddress.WriteFunction == 16) | ||||
|                 return GetWriteModbusCommand(mAddress, value); | ||||
|             else | ||||
|                 return GetWriteOneModbusCommand(mAddress, value); | ||||
|  | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取读取报文 | ||||
|     /// </summary> | ||||
|     private static OperResult<byte[]> GetReadModbusCommand(ModbusAddress mAddress, int length) | ||||
|     { | ||||
|         byte[] array = new byte[6] | ||||
|         { | ||||
|             byte[] array = new byte[6] | ||||
|             { | ||||
|         (byte) mAddress.Station, | ||||
|         (byte)5, | ||||
|         (byte) mAddress.ReadFunction, | ||||
|         BitConverter.GetBytes(mAddress.AddressStart)[1], | ||||
|         BitConverter.GetBytes(mAddress.AddressStart)[0], | ||||
|          0, | ||||
|          0 | ||||
|             }; | ||||
|             if (value) | ||||
|             { | ||||
|                 array[4] = 0xFF; | ||||
|                 array[5] = 0; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 array[4] = 0; | ||||
|                 array[5] = 0; | ||||
|             } | ||||
|             return OperResult.CreateSuccessResult(array); | ||||
|         } | ||||
|         BitConverter.GetBytes(length)[1], | ||||
|         BitConverter.GetBytes(length)[0] | ||||
|         }; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取15写入布尔量报文 | ||||
|         /// </summary> | ||||
|         private static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length) | ||||
|         return OperResult.CreateSuccessResult(array); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取05写入布尔量报文 | ||||
|     /// </summary> | ||||
|     private static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             try | ||||
|             if (address.IndexOf('.') <= 0) | ||||
|             { | ||||
|                 byte[] numArray1 = values.BoolArrayToByte(); | ||||
|                 byte[] numArray2 = new byte[7 + numArray1.Length]; | ||||
|                 numArray2[0] = (byte)mAddress.Station; | ||||
|                 numArray2[1] = (byte)15; | ||||
|                 numArray2[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|                 numArray2[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|                 numArray2[4] = (byte)(length / 256); | ||||
|                 numArray2[5] = (byte)(length % 256); | ||||
|                 numArray2[6] = (byte)numArray1.Length; | ||||
|                 numArray1.CopyTo(numArray2, 7); | ||||
|                 return OperResult.CreateSuccessResult(numArray2); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex.Message); | ||||
|                 ModbusAddress mAddress = new(address, station); | ||||
|                 return GetWriteBoolModbusCommand(mAddress, value); | ||||
|             } | ||||
|             return new("不支持写入字寄存器的某一位"); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取16写入字报文 | ||||
|         /// </summary> | ||||
|         private static OperResult<byte[]> GetWriteModbusCommand(ModbusAddress mAddress, byte[] values) | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             byte[] numArray = new byte[7 + values.Length]; | ||||
|             numArray[0] = (byte)mAddress.Station; | ||||
|             numArray[1] = (byte)16; | ||||
|             numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|             numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|             numArray[4] = (byte)(values.Length / 2 / 256); | ||||
|             numArray[5] = (byte)(values.Length / 2 % 256); | ||||
|             numArray[6] = (byte)values.Length; | ||||
|             values.CopyTo(numArray, 7); | ||||
|             return OperResult.CreateSuccessResult(numArray); | ||||
|  | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 获取6写入字报文 | ||||
|         /// </summary> | ||||
|         private static OperResult<byte[]> GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values) | ||||
|     /// <summary> | ||||
|     /// 获取05写入布尔量报文 | ||||
|     /// </summary> | ||||
|     private static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value) | ||||
|     { | ||||
|         byte[] array = new byte[6] | ||||
|         { | ||||
|             byte[] numArray = new byte[4 + values.Length]; | ||||
|             numArray[0] = (byte)mAddress.Station; | ||||
|             numArray[1] = (byte)6; | ||||
|             numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|             numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|             values.CopyTo(numArray, 4); | ||||
|             return OperResult.CreateSuccessResult(numArray); | ||||
|     (byte) mAddress.Station, | ||||
|     (byte)5, | ||||
|     BitConverter.GetBytes(mAddress.AddressStart)[1], | ||||
|     BitConverter.GetBytes(mAddress.AddressStart)[0], | ||||
|      0, | ||||
|      0 | ||||
|         }; | ||||
|         if (value) | ||||
|         { | ||||
|             array[4] = 0xFF; | ||||
|             array[5] = 0; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             array[4] = 0; | ||||
|             array[5] = 0; | ||||
|         } | ||||
|         return OperResult.CreateSuccessResult(array); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取15写入布尔量报文 | ||||
|     /// </summary> | ||||
|     private static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             byte[] numArray1 = values.BoolArrayToByte(); | ||||
|             byte[] numArray2 = new byte[7 + numArray1.Length]; | ||||
|             numArray2[0] = (byte)mAddress.Station; | ||||
|             numArray2[1] = (byte)15; | ||||
|             numArray2[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|             numArray2[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|             numArray2[4] = (byte)(length / 256); | ||||
|             numArray2[5] = (byte)(length % 256); | ||||
|             numArray2[6] = (byte)numArray1.Length; | ||||
|             numArray1.CopyTo(numArray2, 7); | ||||
|             return OperResult.CreateSuccessResult(numArray2); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取16写入字报文 | ||||
|     /// </summary> | ||||
|     private static OperResult<byte[]> GetWriteModbusCommand(ModbusAddress mAddress, byte[] values) | ||||
|     { | ||||
|         byte[] numArray = new byte[7 + values.Length]; | ||||
|         numArray[0] = (byte)mAddress.Station; | ||||
|         numArray[1] = (byte)16; | ||||
|         numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|         numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|         numArray[4] = (byte)(values.Length / 2 / 256); | ||||
|         numArray[5] = (byte)(values.Length / 2 % 256); | ||||
|         numArray[6] = (byte)values.Length; | ||||
|         values.CopyTo(numArray, 7); | ||||
|         return OperResult.CreateSuccessResult(numArray); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取6写入字报文 | ||||
|     /// </summary> | ||||
|     private static OperResult<byte[]> GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values) | ||||
|     { | ||||
|         byte[] numArray = new byte[4 + values.Length]; | ||||
|         numArray[0] = (byte)mAddress.Station; | ||||
|         numArray[1] = (byte)6; | ||||
|         numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|         numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|         values.CopyTo(numArray, 4); | ||||
|         return OperResult.CreateSuccessResult(numArray); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -48,47 +48,14 @@ public class ModbusRtuDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M | ||||
|         { | ||||
|             request.ResultCode = result.ResultCode; | ||||
|             request.Message = result.Message; | ||||
|             request.Content = result.Content; | ||||
|             return FilterResult.Success; | ||||
|             request.Content = result.Content1; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (response.Length <= 1) | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 //如果长度不足,返回缓存 | ||||
|                 return FilterResult.Cache; | ||||
|             } | ||||
|             if (!(response[1] <= 0x10)) | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 //功能码不对,返回放弃 | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if ((response.Length > response[2] + 4)) | ||||
|                 { | ||||
|                     request.ResultCode = result.ResultCode; | ||||
|                     request.Message = result.Message; | ||||
|                     request.Content = result.Content; | ||||
|                     //如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃 | ||||
|                     return FilterResult.Success; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     request.ResultCode = result.ResultCode; | ||||
|                     request.Message = result.Message; | ||||
|                     request.Content = result.Content; | ||||
|                     //否则返回缓存 | ||||
|                     return FilterResult.Cache; | ||||
|                 } | ||||
|             } | ||||
|             request.ResultCode = result.ResultCode; | ||||
|             request.Message = result.Message; | ||||
|         } | ||||
|         return result.Content2; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| @@ -38,6 +40,7 @@ public class ModbusRtuOverUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAd | ||||
|     protected override OperResult<byte[]> UnpackResponse( | ||||
|               byte[] send, byte[] response) | ||||
|     { | ||||
|         return ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable); | ||||
|         var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable); | ||||
|         return result.Copy(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,13 +10,12 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// ModbusTcpDataHandleAdapter | ||||
| /// </summary> | ||||
| public class ModbusTcpDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusTcpMessage> | ||||
| { | ||||
| @@ -58,48 +57,14 @@ public class ModbusTcpDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<M | ||||
|         { | ||||
|             request.ResultCode = result.ResultCode; | ||||
|             request.Message = result.Message; | ||||
|             request.Content = result.Content; | ||||
|             return FilterResult.Success; | ||||
|             request.Content = result.Content1; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             //如果返回错误,具体分析 | ||||
|             var op = result.Copy<byte[], FilterResult>(); | ||||
|             if (response.Length == 9) | ||||
|             { | ||||
|                 if (response[7] >= 0x80)//错误码 | ||||
|                 { | ||||
|                     request.ResultCode = result.ResultCode; | ||||
|                     request.Message = result.Message; | ||||
|                     request.Content = result.Content; | ||||
|                     return FilterResult.Success; | ||||
|                 } | ||||
|             } | ||||
|             if (response.Length < 10) | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 return FilterResult.Cache; | ||||
|                 //如果长度不足,返回缓存 | ||||
|             } | ||||
|             if ((response.Length > response[8] + 9)) | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 return FilterResult.Success; | ||||
|                 //如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃 | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 return FilterResult.Cache; | ||||
|                 //否则返回缓存 | ||||
|             } | ||||
|             request.ResultCode = result.ResultCode; | ||||
|             request.Message = result.Message; | ||||
|         } | ||||
|         return result.Content2; | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
| @@ -50,6 +51,7 @@ public class ModbusUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAdapter<M | ||||
|     /// <inheritdoc/> | ||||
|     protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response) | ||||
|     { | ||||
|         return ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6)); | ||||
|         var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6)); | ||||
|         return result.Copy(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> | ||||
| 		<TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks> | ||||
| 		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks> | ||||
|  | ||||
| 	</PropertyGroup> | ||||
| 	 | ||||
|   | ||||
| @@ -38,6 +38,14 @@ | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.Parse(System.String,System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ParseFrom(System.String,System.Int32)"> | ||||
|             <summary> | ||||
|             解析地址 | ||||
|             </summary> | ||||
|             <param name="address"></param> | ||||
|             <param name="length"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ToString"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
| @@ -458,7 +466,7 @@ | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             ModbusTcpDataHandleAdapter | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter.IsCheckMessageId"> | ||||
|   | ||||
| @@ -301,54 +301,99 @@ public class OPCDAClient : DisposableObject | ||||
|         return OPCNode?.ToString(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入值 | ||||
|     /// 批量写入值 | ||||
|     /// </summary> | ||||
|     /// <param name="valueName">写入</param> | ||||
|     /// <param name="value"></param> | ||||
|     /// <returns></returns> | ||||
|     public OperResult WriteItem(string valueName, JToken value) | ||||
|     public Dictionary<string, OperResult> WriteItem(Dictionary<string, JToken> writeInfos) | ||||
|     { | ||||
|         Dictionary<string, OperResult> results = new(); | ||||
|         if (PrivateConnect()) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 var group = Groups.FirstOrDefault(it => it.OpcItems.Any(a => a.ItemID == valueName)); | ||||
|                 if (group == null) | ||||
|                     return new OperResult("不存在该变量" + valueName); | ||||
|                 var item = group.OpcItems.Where(it => it.ItemID == valueName).FirstOrDefault(); | ||||
|                 int[] serverHandle = new int[1] { item.ServerHandle }; | ||||
|                 int[] PErrors = new int[1]; | ||||
|                 var jtoken = value; | ||||
|                 var rank = jtoken.CalculateActualValueRank(); | ||||
|                 object rawWriteValue; | ||||
|                 switch (rank) | ||||
|                 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) | ||||
|                 { | ||||
|                     case -1: | ||||
|                         rawWriteValue = ((JValue)jtoken).Value; | ||||
|                         break; | ||||
|                     default: | ||||
|                         var jarray = ((JArray)jtoken); | ||||
|                         rawWriteValue = jarray.Select(j => (object)j).ToArray(); | ||||
|                         break; | ||||
|                     if (item1.Key == null) | ||||
|                     { | ||||
|                         foreach (var item2 in item1) | ||||
|                         { | ||||
|                             results.Add(item2.Key, new OperResult("不存在该变量" + item2.Key)); | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         List<int> ServerHandles = 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); | ||||
|                             var jtoken = item2.Value; | ||||
|                             var rank = jtoken.CalculateActualValueRank(); | ||||
|                             object rawWriteValue; | ||||
|                             switch (rank) | ||||
|                             { | ||||
|                                 case -1: | ||||
|                                     rawWriteValue = ((JValue)jtoken).Value; | ||||
|                                     break; | ||||
|                                 default: | ||||
|                                     var jarray = ((JArray)jtoken); | ||||
|                                     rawWriteValue = jarray.Select(j => (object)j).ToArray(); | ||||
|                                     break; | ||||
|                             } | ||||
|  | ||||
|                             Values.Add(rawWriteValue); | ||||
|  | ||||
|                         } | ||||
|  | ||||
|                         var result = item1.Key.Write(Values.ToArray(), ServerHandles.ToArray(), out var PErrors); | ||||
|                         var data = item1.ToList(); | ||||
|                         for (int i = 0; i < data.Count; i++) | ||||
|                         { | ||||
|                             results.Add(data[i].Key, PErrors[i] == 0 ? OperResult.CreateSuccessResult() : new OperResult("错误代码:" + PErrors[i])); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 object[] Value = new object[1] { rawWriteValue }; | ||||
|                 var result = group.Write(Value, serverHandle, out PErrors); | ||||
|                 return result; | ||||
|                 return results; | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult(ex.Message); | ||||
|                 var keys = writeInfos.Keys.ToList(); | ||||
|                 foreach (var item in keys) | ||||
|                 { | ||||
|                     results.AddOrUpdate(item, new(ex)); | ||||
|                 } | ||||
|                 return results; | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         return new OperResult(); | ||||
|         else | ||||
|         { | ||||
|             var keys = writeInfos.Keys.ToList(); | ||||
|             foreach (var item in keys) | ||||
|             { | ||||
|                 results.AddOrUpdate(item, new("未初始化连接")); | ||||
|             } | ||||
|             return results; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void Dispose(bool disposing) | ||||
|     { | ||||
|         PrivateDisconnect(); | ||||
|         checkLock.SafeDispose(); | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> | ||||
| 		<TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks> | ||||
| 		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks> | ||||
|  | ||||
| 	</PropertyGroup> | ||||
|  | ||||
|   | ||||
| @@ -520,12 +520,10 @@ | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ToString"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.WriteItem(System.String,Newtonsoft.Json.Linq.JToken)"> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.WriteItem(System.Collections.Generic.Dictionary{System.String,Newtonsoft.Json.Linq.JToken})"> | ||||
|             <summary> | ||||
|             写入值 | ||||
|             批量写入值 | ||||
|             </summary> | ||||
|             <param name="valueName">写入</param> | ||||
|             <param name="value"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Dispose(System.Boolean)"> | ||||
|   | ||||
| @@ -109,7 +109,6 @@ public static class JsonUtils | ||||
|         { | ||||
|             if (ValueRank == ValueRanks.Scalar) | ||||
|             { | ||||
|                 Type type = TypeInfo.GetSystemType(builtInType, ValueRank); | ||||
|                 switch (builtInType) | ||||
|                 { | ||||
|                     case BuiltInType.Null: { var variant = decoder.ReadVariant(fieldName); return variant.Value; } | ||||
| @@ -124,7 +123,7 @@ public static class JsonUtils | ||||
|                     case BuiltInType.UInt64: { return decoder.ReadUInt64(fieldName); } | ||||
|                     case BuiltInType.Float: { return decoder.ReadFloat(fieldName); } | ||||
|                     case BuiltInType.Double: { return decoder.ReadDouble(fieldName); } | ||||
|                     case BuiltInType.String: { return decoder.ReadString(fieldName); } | ||||
|                     case BuiltInType.String: { return decoder.ReadField(fieldName, out var token) ? token?.ToString() : null; } | ||||
|                     case BuiltInType.DateTime: { return decoder.ReadDateTime(fieldName); } | ||||
|                     case BuiltInType.Guid: { return decoder.ReadGuid(fieldName); } | ||||
|                     case BuiltInType.ByteString: { return decoder.ReadByteString(fieldName); } | ||||
| @@ -138,7 +137,8 @@ public static class JsonUtils | ||||
|                     case BuiltInType.DataValue: { return decoder.ReadDataValue(fieldName); } | ||||
|                     case BuiltInType.Enumeration: | ||||
|                         { | ||||
|                             return type.IsEnum ? decoder.ReadEnumerated(fieldName, type) : (object)decoder.ReadInt32(fieldName); | ||||
|                             Type type = TypeInfo.GetSystemType(builtInType, ValueRank); | ||||
|                             return type.IsEnum ? decoder.ReadEnumerated(fieldName, type) : decoder.ReadInt32(fieldName); | ||||
|                         } | ||||
|                     case BuiltInType.DiagnosticInfo: { return decoder.ReadDiagnosticInfo(fieldName); } | ||||
|                     case BuiltInType.Variant: { return decoder.ReadVariant(fieldName); } | ||||
| @@ -300,7 +300,7 @@ public static class JsonUtils | ||||
|                 case BuiltInType.DataValue: { encoder.WriteDataValue(fieldName, (DataValue)value); return; } | ||||
|                 case BuiltInType.Enumeration: | ||||
|                     { | ||||
|                         if (value.GetType().IsEnum) | ||||
|                         if (value?.GetType().IsEnum == true) | ||||
|                         { | ||||
|                             encoder.WriteEnumerated(fieldName, (Enum)value); | ||||
|                         } | ||||
|   | ||||
| @@ -69,7 +69,10 @@ public class OPCUAClient : DisposableObject | ||||
|     private readonly ApplicationInstance m_application = new(); | ||||
|  | ||||
|     private readonly ApplicationConfiguration m_configuration; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// SessionReconnectHandler | ||||
|     /// </summary> | ||||
|     public SessionReconnectHandler ReConnectHandler => m_reConnectHandler; | ||||
|     private SessionReconnectHandler m_reConnectHandler; | ||||
|     private ISession m_session; | ||||
|     /// <summary> | ||||
| @@ -230,7 +233,7 @@ public class OPCUAClient : DisposableObject | ||||
|                     StartNodeId = variableNode.NodeId, | ||||
|                     AttributeId = Attributes.Value, | ||||
|                     DisplayName = items[i], | ||||
|                     Filter = new DataChangeFilter() { DeadbandValue = OPCNode.DeadBand, DeadbandType = (int)DeadbandType.Absolute, Trigger = DataChangeTrigger.StatusValue }, | ||||
|                     Filter = OPCNode.DeadBand == 0 ? null : new DataChangeFilter() { DeadbandValue = OPCNode.DeadBand, DeadbandType = (int)DeadbandType.Absolute, Trigger = DataChangeTrigger.StatusValue }, | ||||
|                     SamplingInterval = OPCNode?.UpdateRate ?? 1000, | ||||
|                 }; | ||||
|                 await typeSystem.LoadType(variableNode.DataType, true, true); | ||||
| @@ -249,7 +252,7 @@ public class OPCUAClient : DisposableObject | ||||
|         m_subscription.Create(); | ||||
|         foreach (var item in m_subscription.MonitoredItems.Where(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode))) | ||||
|         { | ||||
|             item.Filter = new DataChangeFilter() { DeadbandValue = OPCNode.DeadBand, DeadbandType = (int)DeadbandType.None, Trigger = DataChangeTrigger.StatusValue }; | ||||
|             item.Filter = OPCNode.DeadBand == 0 ? null : new DataChangeFilter() { DeadbandValue = OPCNode.DeadBand, DeadbandType = (int)DeadbandType.None, Trigger = DataChangeTrigger.StatusValue }; | ||||
|         } | ||||
|         m_subscription.ApplyChanges(); | ||||
|  | ||||
| @@ -320,12 +323,21 @@ public class OPCUAClient : DisposableObject | ||||
|             VariableNode variableNode = (VariableNode)ReadNode(monitoreditem.StartNodeId.ToString(), false); | ||||
|             foreach (var value in monitoreditem.DequeueValues()) | ||||
|             { | ||||
|                 var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value); | ||||
|                 if (data == null && value.Value != null) | ||||
|                 if (value.Value != null) | ||||
|                 { | ||||
|                     Log.Warning($"{monitoreditem.StartNodeId}转换出错,原始值String为{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) | ||||
|                     { | ||||
|                         Log.Warning($"{monitoreditem.StartNodeId}转换出错,原始值String为{value.Value}"); | ||||
|                     } | ||||
|                     DataChangedHandler?.Invoke((variableNode, value, data)); | ||||
|                 } | ||||
|                 DataChangedHandler?.Invoke((variableNode, value, data)); | ||||
|                 else | ||||
|                 { | ||||
|                     var data = JValue.CreateNull(); | ||||
|                     DataChangedHandler?.Invoke((variableNode, value, data)); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -512,29 +524,33 @@ public class OPCUAClient : DisposableObject | ||||
|     /// <summary> | ||||
|     /// 异步写opc标签 | ||||
|     /// </summary> | ||||
|     public async Task<OperResult> WriteNodeAsync(string tag, JToken value, CancellationToken token = default) | ||||
|     public async Task<Dictionary<string, OperResult>> WriteNodeAsync(Dictionary<string, JToken> writeInfoLists, CancellationToken token = default) | ||||
|     { | ||||
|         Dictionary<string, OperResult> results = new(); | ||||
|         try | ||||
|         { | ||||
|             WriteValue valueToWrite = new() | ||||
|             WriteValueCollection valuesToWrite = new(); | ||||
|             foreach (var item in writeInfoLists) | ||||
|             { | ||||
|                 NodeId = new NodeId(tag), | ||||
|                 AttributeId = Attributes.Value, | ||||
|             }; | ||||
|             var variableNode = (VariableNode)ReadNode(tag.ToString(), false); | ||||
|             await typeSystem.LoadType(variableNode.DataType, true, true); | ||||
|             var dataValue = JsonUtils.Decode( | ||||
|                 m_session.MessageContext, | ||||
|                 variableNode.DataType, | ||||
|                 TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), | ||||
|                 value.CalculateActualValueRank(), | ||||
|                 value | ||||
|                 ); | ||||
|             valueToWrite.Value = dataValue; | ||||
|             WriteValueCollection valuesToWrite = new() | ||||
|             { | ||||
|                 valueToWrite | ||||
|             }; | ||||
|                 WriteValue valueToWrite = new() | ||||
|                 { | ||||
|                     NodeId = new NodeId(item.Key), | ||||
|                     AttributeId = Attributes.Value, | ||||
|                 }; | ||||
|                 var variableNode = (VariableNode)ReadNode(item.Key, false); | ||||
|                 await typeSystem.LoadType(variableNode.DataType, true, true); | ||||
|                 var dataValue = JsonUtils.Decode( | ||||
|                     m_session.MessageContext, | ||||
|                     variableNode.DataType, | ||||
|                     TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), | ||||
|                     item.Value.CalculateActualValueRank(), | ||||
|                     item.Value | ||||
|                     ); | ||||
|                 valueToWrite.Value = dataValue; | ||||
|  | ||||
|                 valuesToWrite.Add(valueToWrite); | ||||
|             } | ||||
|  | ||||
|  | ||||
|             var result = await m_session.WriteAsync( | ||||
|      requestHeader: null, | ||||
| @@ -542,15 +558,29 @@ public class OPCUAClient : DisposableObject | ||||
|  | ||||
|             ClientBase.ValidateResponse(result.Results, valuesToWrite); | ||||
|             ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, valuesToWrite); | ||||
|             if (!StatusCode.IsGood(result.Results[0])) | ||||
|  | ||||
|  | ||||
|             var keys = writeInfoLists.Keys.ToList(); | ||||
|             for (int i = 0; i < keys.Count; i++) | ||||
|             { | ||||
|                 return new OperResult(result.Results[0].ToString()); | ||||
|                 if (!StatusCode.IsGood(result.Results[i])) | ||||
|                     results.Add(keys[i], new(result.Results[i].ToString())); | ||||
|                 else | ||||
|                 { | ||||
|                     results.Add(keys[i], OperResult.CreateSuccessResult()); | ||||
|                 } | ||||
|             } | ||||
|             return OperResult.CreateSuccessResult(); | ||||
|  | ||||
|             return results; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|             var keys = writeInfoLists.Keys.ToList(); | ||||
|             foreach (var item in keys) | ||||
|             { | ||||
|                 results.Add(item, new(ex)); | ||||
|             } | ||||
|             return results; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| @@ -855,6 +885,7 @@ public class OPCUAClient : DisposableObject | ||||
|     protected override void Dispose(bool disposing) | ||||
|     { | ||||
|         Disconnect(); | ||||
|         checkLock.SafeDispose(); | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -286,6 +286,11 @@ | ||||
|             当前的订阅组,组名称/组 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReConnectHandler"> | ||||
|             <summary> | ||||
|             SessionReconnectHandler | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.#ctor(TouchSocket.Core.ILog)"> | ||||
|             <summary> | ||||
|             默认的构造函数,实例化一个新的OPC UA类 | ||||
| @@ -375,7 +380,7 @@ | ||||
|             从服务器读取值 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.WriteNodeAsync(System.String,Newtonsoft.Json.Linq.JToken,System.Threading.CancellationToken)"> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.WriteNodeAsync(System.Collections.Generic.Dictionary{System.String,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             异步写opc标签 | ||||
|             </summary> | ||||
|   | ||||
| @@ -124,7 +124,7 @@ internal partial class SiemensHelper | ||||
|         } | ||||
|  | ||||
|         byte err = content[21]; | ||||
|         if (err == byte.MaxValue) | ||||
|         if (err != byte.MaxValue) | ||||
|         { | ||||
|             return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21])); | ||||
|         } | ||||
| @@ -301,7 +301,7 @@ internal partial class SiemensHelper | ||||
|             { | ||||
|                 return new OperResult<string>("在PLC中不是字符串类型"); | ||||
|             } | ||||
|             var result2 = await plc.ReadAsync(address, 2 + result1.Content[1]); | ||||
|             var result2 = await plc.ReadAsync(address, 2 + result1.Content[1], token); | ||||
|             if (!result2.IsSuccess) | ||||
|             { | ||||
|                 return result2.Copy<string>(); | ||||
|   | ||||
| @@ -54,32 +54,9 @@ public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapte | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|         if (result.IsSuccess) | ||||
|         { | ||||
|             request.ResultCode = result.ResultCode; | ||||
|             request.Message = result.Message; | ||||
|             request.Content = result.Content; | ||||
|             return FilterResult.Success; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             //如果返回错误,具体分析 | ||||
|             if (response.Length < 21) | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 //如果长度不足,返回缓存 | ||||
|                 return FilterResult.Cache; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 request.ResultCode = result.ResultCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|                 //如果长度已经超了,说明这段报文已经不能继续解析了,直接返回放弃 | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|         } | ||||
|         request.ResultCode = result.ResultCode; | ||||
|         request.Message = result.Message; | ||||
|         request.Content = result.Content; | ||||
|         return FilterResult.Success; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>--> | ||||
| 		<TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks> | ||||
| 		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks> | ||||
|  | ||||
| 	</PropertyGroup> | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,121 @@ | ||||
| #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.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| using ThingsGateway.Application; | ||||
| using ThingsGateway.Foundation; | ||||
| using ThingsGateway.Foundation.Serial; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
| using TouchSocket.Sockets; | ||||
|  | ||||
| namespace ThingsGateway.DLT645; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class DLT645_2007 : CollectBase | ||||
| { | ||||
|     private readonly DLT645_2007Property driverPropertys = new(); | ||||
|     /// <inheritdoc/> | ||||
|     protected override IReadWriteDevice PLC => _plc; | ||||
|     private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007 _plc; | ||||
|     /// <inheritdoc/> | ||||
|     public override Type DriverDebugUIType => typeof(DLT645_2007DebugDriverPage); | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public override bool IsSupportRequest => true; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override Task AfterStopAsync() | ||||
|     { | ||||
|         _plc?.Disconnect(); | ||||
|         return Task.CompletedTask; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task BeforStartAsync(CancellationToken token) | ||||
|     { | ||||
|         await _plc?.ConnectAsync(token); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     protected override void Dispose(bool disposing) | ||||
|     { | ||||
|         _plc?.Disconnect(); | ||||
|         _plc?.SafeDispose(); | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void InitDataAdapter() | ||||
|     { | ||||
|         _plc.SetDataAdapter(); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override bool IsConnected() | ||||
|     { | ||||
|         return _plc?.SerialClient?.CanSend == true; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) | ||||
|     { | ||||
|         return deviceVariables.LoadSourceRead(_plc); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) | ||||
|     { | ||||
|         if (client == null) | ||||
|         { | ||||
|             FoundataionConfig.SetSerialProperty(new() | ||||
|             { | ||||
|                 PortName = driverPropertys.PortName, | ||||
|                 BaudRate = driverPropertys.BaudRate, | ||||
|                 DataBits = driverPropertys.DataBits, | ||||
|                 Parity = driverPropertys.Parity, | ||||
|                 StopBits = driverPropertys.StopBits, | ||||
|             }) | ||||
|                 .SetBufferLength(1024); | ||||
|             client = new SerialClient(); | ||||
|             ((SerialClient)client).Setup(FoundataionConfig); | ||||
|         } | ||||
|         //载入配置 | ||||
|         _plc = new((SerialClient)client) | ||||
|         { | ||||
|             FrameTime = driverPropertys.FrameTime, | ||||
|             CacheTimeout = driverPropertys.CacheTimeout, | ||||
|             DataFormat = driverPropertys.DataFormat, | ||||
|             EnableFEHead = driverPropertys.EnableFEHead, | ||||
|             OperCode = driverPropertys.OperCode, | ||||
|             Password = driverPropertys.Password, | ||||
|             Station = driverPropertys.Station, | ||||
|             TimeOut = driverPropertys.TimeOut | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token) | ||||
|     { | ||||
|         return await _plc.ReadAsync(address, length, token); | ||||
|     } | ||||
|  | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user