Compare commits
	
		
			178 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | a64ab7df4e | ||
|   | 82cd64cb50 | ||
|   | 065bfb8694 | ||
|   | 6db335cf87 | ||
|   | 155f4670e9 | ||
|   | 50522b571a | ||
|   | 8e138863ce | ||
|   | 7d8dfe628d | ||
|   | 8baed5b306 | ||
|   | 41a5ffd214 | ||
|   | c6aec3a1af | ||
|   | 22e30f7a62 | ||
|   | 57711b8ab5 | ||
|   | 90ff1259ea | ||
|   | d88fc5ccd7 | ||
|   | 5aaca2aa9c | ||
|   | 8b9ca56e17 | ||
|   | e4f3772e6d | ||
|   | d58ec81d20 | ||
|   | 415aae44b6 | ||
|   | a533286658 | ||
|   | e59f91cd82 | ||
|   | 5f8b85d8a4 | ||
|   | 47c7b88436 | ||
|   | 90006782f2 | ||
|   | c3d49cbe70 | ||
|   | 112323a360 | ||
|   | 9d08c90fda | ||
|   | 602d24deec | ||
|   | a2b9f66785 | ||
|   | 7cbf289b50 | ||
|   | 4097da79a5 | ||
|   | 91b7ae554f | ||
|   | 3121aa2542 | ||
|   | 4bf895e6e1 | ||
|   | 0c5489e920 | ||
|   | d63c3aaa80 | ||
|   | 4f188ea6cc | ||
|   | acb17018ae | ||
|   | 2affe2988d | ||
|   | 4174dd2206 | ||
|   | e1c492f238 | ||
|   | fb08e34fa3 | ||
|   | a1793a0afe | ||
|   | 4da9763b49 | ||
|   | 81e0918bd0 | ||
|   | c1e064f06d | ||
|   | 1c52be8b47 | ||
|   | bcd82055ca | ||
|   | c47d95d170 | ||
|   | 3e62f1ad51 | ||
|   | 8dcae973ef | ||
|   | 4cf35f7294 | ||
|   | 94c77d151b | ||
|   | 7f600e2b4b | ||
|   | c809d0ba87 | ||
|   | 50f038ec89 | ||
|   | 9199a255a2 | ||
|   | d324537b47 | ||
|   | d0c05685f7 | ||
|   | 1063c930b5 | ||
|   | 79cbd44366 | ||
|   | 7fdac1c5cb | ||
|   | 0c0cf72ebb | ||
|   | 8e2fe175ed | ||
|   | d1cff037c9 | ||
|   | fc88a2fafa | ||
|   | 45fcceb056 | ||
|   | 7043477038 | ||
|   | 7dd685cf54 | ||
|   | 5f5e4969c0 | ||
|   | 8a53fd19e9 | ||
|   | baf4714c36 | ||
|   | 7ba9ac7a5b | ||
|   | 85b8f26e8e | ||
|   | 594a0f1410 | ||
|   | d317d757d7 | ||
|   | fdf0ba6318 | ||
|   | 15bf7de5fa | ||
|   | d3402b058e | ||
|   | e7dfdd4031 | ||
|   | b2dd7b6364 | ||
|   | 9bd6d9abbf | ||
|   | cd14428fea | ||
|   | 19d9f03c2b | ||
|   | 0d57e72bbf | ||
|   | 329516a61b | ||
|   | d566869589 | ||
|   | 9cb8d8e6c7 | ||
|   | 9de3c57e5d | ||
|   | f32ff92b0b | ||
|   | 88d71e271e | ||
|   | fd9c14612a | ||
|   | e26e5a160f | ||
|   | b836bfed22 | ||
|   | a4b598c6d0 | ||
|   | c9ab755839 | ||
|   | 9920edba53 | ||
|   | 12bd7280d1 | ||
|   | d30ea7f63b | ||
|   | ebd3390db6 | ||
|   | 9a374a9ebc | ||
|   | b1bc22cb08 | ||
|   | 4930d53890 | ||
|   | c31327b5bc | ||
|   | 3f2aa1f1e1 | ||
|   | 6e78c00a96 | ||
|   | c27dde085e | ||
|   | d26cc308c0 | ||
|   | fb1efdf290 | ||
|   | 3c99f2a472 | ||
|   | affe9a44e0 | ||
|   | 43730fa519 | ||
|   | d39aa22b09 | ||
|   | e232a6b6ea | ||
|   | 71ebb36fe9 | ||
|   | 78a0b86327 | ||
|   | 2636c16a97 | ||
|   | fd77c0242d | ||
|   | e74819a900 | ||
|   | 9b7f696c9b | ||
|   | 0230d614e7 | ||
|   | 252d99ad78 | ||
|   | 1ffc200350 | ||
|   | 807d89b2b2 | ||
|   | 4013afa1f1 | ||
|   | a580927ceb | ||
|   | bf2cf52034 | ||
|   | 81bb8b7c31 | ||
|   | a825007fb5 | ||
|   | 988124d96a | ||
|   | f0de815296 | ||
|   | 0e2d58c887 | ||
|   | b155382626 | ||
|   | f362d740af | ||
|   | 4a85e31a4f | ||
|   | 302c270ad5 | ||
|   | 3c1517d0f3 | ||
|   | f9fb222044 | ||
|   | e8edc02ba3 | ||
|   | 95a44e3053 | ||
|   | 74a9fe9a87 | ||
|   | 4d03f9ea1a | ||
|   | 67c96ca991 | ||
|   | 88fb793c68 | ||
|   | d6d02d8cc5 | ||
|   | c5a3f8e2e3 | ||
|   | 27e8653a1a | ||
|   | 863beda82c | ||
|   | bac84c3ecd | ||
|   | 2fca2ad9f8 | ||
|   | dd75286fe0 | ||
|   | 7f91792cf1 | ||
|   | 0e0ccad311 | ||
|   | 0691f72e67 | ||
|   | 7e38a51720 | ||
|   | 34ca8243a3 | ||
|   | 112fea7632 | ||
|   | 378763e4ee | ||
|   | 517bd0394d | ||
|   | 70adb97fb5 | ||
|   | 623d44cabe | ||
|   | 0d479ca00b | ||
|   | 8bc49ef437 | ||
|   | f83fcec786 | ||
|   | 93690ce40d | ||
|   | f82c5f2f27 | ||
|   | a83c1c3899 | ||
|   | 91d6aed109 | ||
|   | db8f8fe51d | ||
|   | 4596004b17 | ||
|   | d5540906cb | ||
|   | 90796a979d | ||
|   | 2190a87772 | ||
|   | c5953b83f8 | ||
|   | 24bc60abf0 | ||
|   | 31eee6b009 | ||
|   | c5da565a8f | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -363,4 +363,6 @@ MigrationBackup/ | |||||||
| FodyWeavers.xsd | FodyWeavers.xsd | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /framework/*pro* | ||||||
| /framework/*Pro* | /framework/*Pro* | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +0,0 @@ | |||||||
| [*.cs] |  | ||||||
|  |  | ||||||
| # CA1848: 使用 LoggerMessage 委托 |  | ||||||
| dotnet_diagnostic.CA1848.severity = none |  | ||||||
|  |  | ||||||
| # CA2254: 模板应为静态表达式 |  | ||||||
| dotnet_diagnostic.CA2254.severity = suggestion |  | ||||||
							
								
								
									
										63
									
								
								framework/.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								framework/.gitattributes
									
									
									
									
										vendored
									
									
								
							| @@ -1,63 +0,0 @@ | |||||||
| ############################################################################### |  | ||||||
| # Set default behavior to automatically normalize line endings. |  | ||||||
| ############################################################################### |  | ||||||
| * text=auto |  | ||||||
|  |  | ||||||
| ############################################################################### |  | ||||||
| # Set default behavior for command prompt diff. |  | ||||||
| # |  | ||||||
| # This is need for earlier builds of msysgit that does not have it on by |  | ||||||
| # default for csharp files. |  | ||||||
| # Note: This is only used by command line |  | ||||||
| ############################################################################### |  | ||||||
| #*.cs     diff=csharp |  | ||||||
|  |  | ||||||
| ############################################################################### |  | ||||||
| # Set the merge driver for project and solution files |  | ||||||
| # |  | ||||||
| # Merging from the command prompt will add diff markers to the files if there |  | ||||||
| # are conflicts (Merging from VS is not affected by the settings below, in VS |  | ||||||
| # the diff markers are never inserted). Diff markers may cause the following  |  | ||||||
| # file extensions to fail to load in VS. An alternative would be to treat |  | ||||||
| # these files as binary and thus will always conflict and require user |  | ||||||
| # intervention with every merge. To do so, just uncomment the entries below |  | ||||||
| ############################################################################### |  | ||||||
| #*.sln       merge=binary |  | ||||||
| #*.csproj    merge=binary |  | ||||||
| #*.vbproj    merge=binary |  | ||||||
| #*.vcxproj   merge=binary |  | ||||||
| #*.vcproj    merge=binary |  | ||||||
| #*.dbproj    merge=binary |  | ||||||
| #*.fsproj    merge=binary |  | ||||||
| #*.lsproj    merge=binary |  | ||||||
| #*.wixproj   merge=binary |  | ||||||
| #*.modelproj merge=binary |  | ||||||
| #*.sqlproj   merge=binary |  | ||||||
| #*.wwaproj   merge=binary |  | ||||||
|  |  | ||||||
| ############################################################################### |  | ||||||
| # behavior for image files |  | ||||||
| # |  | ||||||
| # image files are treated as binary by default. |  | ||||||
| ############################################################################### |  | ||||||
| #*.jpg   binary |  | ||||||
| #*.png   binary |  | ||||||
| #*.gif   binary |  | ||||||
|  |  | ||||||
| ############################################################################### |  | ||||||
| # diff behavior for common document formats |  | ||||||
| #  |  | ||||||
| # Convert binary document formats to text before diffing them. This feature |  | ||||||
| # is only available from the command line. Turn it on by uncommenting the  |  | ||||||
| # entries below. |  | ||||||
| ############################################################################### |  | ||||||
| #*.doc   diff=astextplain |  | ||||||
| #*.DOC   diff=astextplain |  | ||||||
| #*.docx  diff=astextplain |  | ||||||
| #*.DOCX  diff=astextplain |  | ||||||
| #*.dot   diff=astextplain |  | ||||||
| #*.DOT   diff=astextplain |  | ||||||
| #*.pdf   diff=astextplain |  | ||||||
| #*.PDF   diff=astextplain |  | ||||||
| #*.rtf   diff=astextplain |  | ||||||
| #*.RTF   diff=astextplain |  | ||||||
							
								
								
									
										364
									
								
								framework/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										364
									
								
								framework/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,364 +0,0 @@ | |||||||
| ## Ignore Visual Studio temporary files, build results, and |  | ||||||
| ## files generated by popular Visual Studio add-ons. |  | ||||||
| ## |  | ||||||
| ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore |  | ||||||
|  |  | ||||||
| # User-specific files |  | ||||||
| *.rsuser |  | ||||||
| *.suo |  | ||||||
| *.user |  | ||||||
| *.userosscache |  | ||||||
| *.sln.docstates |  | ||||||
|  |  | ||||||
| # User-specific files (MonoDevelop/Xamarin Studio) |  | ||||||
| *.userprefs |  | ||||||
|  |  | ||||||
| # Mono auto generated files |  | ||||||
| mono_crash.* |  | ||||||
|  |  | ||||||
| # Build results |  | ||||||
| [Dd]ebug/ |  | ||||||
| [Dd]ebugPublic/ |  | ||||||
| [Rr]elease/ |  | ||||||
| [Rr]eleases/ |  | ||||||
| x64/ |  | ||||||
| x86/ |  | ||||||
| [Ww][Ii][Nn]32/ |  | ||||||
| [Aa][Rr][Mm]/ |  | ||||||
| [Aa][Rr][Mm]64/ |  | ||||||
| bld/ |  | ||||||
| [Bb]in/ |  | ||||||
| [Oo]bj/ |  | ||||||
| [Oo]ut/ |  | ||||||
| [Ll]og/ |  | ||||||
| [Ll]ogs/ |  | ||||||
|  |  | ||||||
| # Visual Studio 2015/2017 cache/options directory |  | ||||||
| .vs/ |  | ||||||
| # Uncomment if you have tasks that create the project's static files in wwwroot |  | ||||||
| #wwwroot/ |  | ||||||
|  |  | ||||||
| # Visual Studio 2017 auto generated files |  | ||||||
| Generated\ Files/ |  | ||||||
|  |  | ||||||
| # MSTest test Results |  | ||||||
| [Tt]est[Rr]esult*/ |  | ||||||
| [Bb]uild[Ll]og.* |  | ||||||
|  |  | ||||||
| # NUnit |  | ||||||
| *.VisualState.xml |  | ||||||
| TestResult.xml |  | ||||||
| nunit-*.xml |  | ||||||
|  |  | ||||||
| # Build Results of an ATL Project |  | ||||||
| [Dd]ebugPS/ |  | ||||||
| [Rr]eleasePS/ |  | ||||||
| dlldata.c |  | ||||||
|  |  | ||||||
| # Benchmark Results |  | ||||||
| BenchmarkDotNet.Artifacts/ |  | ||||||
|  |  | ||||||
| # .NET Core |  | ||||||
| project.lock.json |  | ||||||
| project.fragment.lock.json |  | ||||||
| artifacts/ |  | ||||||
|  |  | ||||||
| # ASP.NET Scaffolding |  | ||||||
| ScaffoldingReadMe.txt |  | ||||||
|  |  | ||||||
| # StyleCop |  | ||||||
| StyleCopReport.xml |  | ||||||
|  |  | ||||||
| # Files built by Visual Studio |  | ||||||
| *_i.c |  | ||||||
| *_p.c |  | ||||||
| *_h.h |  | ||||||
| *.ilk |  | ||||||
| *.meta |  | ||||||
| *.obj |  | ||||||
| *.iobj |  | ||||||
| *.pch |  | ||||||
| *.pdb |  | ||||||
| *.ipdb |  | ||||||
| *.pgc |  | ||||||
| *.pgd |  | ||||||
| *.rsp |  | ||||||
| *.sbr |  | ||||||
| *.tlb |  | ||||||
| *.tli |  | ||||||
| *.tlh |  | ||||||
| *.tmp |  | ||||||
| *.tmp_proj |  | ||||||
| *_wpftmp.csproj |  | ||||||
| *.log |  | ||||||
| *.vspscc |  | ||||||
| *.vssscc |  | ||||||
| .builds |  | ||||||
| *.pidb |  | ||||||
| *.svclog |  | ||||||
| *.scc |  | ||||||
|  |  | ||||||
| # Chutzpah Test files |  | ||||||
| _Chutzpah* |  | ||||||
|  |  | ||||||
| # Visual C++ cache files |  | ||||||
| ipch/ |  | ||||||
| *.aps |  | ||||||
| *.ncb |  | ||||||
| *.opendb |  | ||||||
| *.opensdf |  | ||||||
| *.sdf |  | ||||||
| *.cachefile |  | ||||||
| *.VC.db |  | ||||||
| *.VC.VC.opendb |  | ||||||
|  |  | ||||||
| # Visual Studio profiler |  | ||||||
| *.psess |  | ||||||
| *.vsp |  | ||||||
| *.vspx |  | ||||||
| *.sap |  | ||||||
|  |  | ||||||
| # Visual Studio Trace Files |  | ||||||
| *.e2e |  | ||||||
|  |  | ||||||
| # TFS 2012 Local Workspace |  | ||||||
| $tf/ |  | ||||||
|  |  | ||||||
| # Guidance Automation Toolkit |  | ||||||
| *.gpState |  | ||||||
|  |  | ||||||
| # ReSharper is a .NET coding add-in |  | ||||||
| _ReSharper*/ |  | ||||||
| *.[Rr]e[Ss]harper |  | ||||||
| *.DotSettings.user |  | ||||||
|  |  | ||||||
| # TeamCity is a build add-in |  | ||||||
| _TeamCity* |  | ||||||
|  |  | ||||||
| # DotCover is a Code Coverage Tool |  | ||||||
| *.dotCover |  | ||||||
|  |  | ||||||
| # AxoCover is a Code Coverage Tool |  | ||||||
| .axoCover/* |  | ||||||
| !.axoCover/settings.json |  | ||||||
|  |  | ||||||
| # Coverlet is a free, cross platform Code Coverage Tool |  | ||||||
| coverage*.json |  | ||||||
| coverage*.xml |  | ||||||
| coverage*.info |  | ||||||
|  |  | ||||||
| # Visual Studio code coverage results |  | ||||||
| *.coverage |  | ||||||
| *.coveragexml |  | ||||||
|  |  | ||||||
| # NCrunch |  | ||||||
| _NCrunch_* |  | ||||||
| .*crunch*.local.xml |  | ||||||
| nCrunchTemp_* |  | ||||||
|  |  | ||||||
| # MightyMoose |  | ||||||
| *.mm.* |  | ||||||
| AutoTest.Net/ |  | ||||||
|  |  | ||||||
| # Web workbench (sass) |  | ||||||
| .sass-cache/ |  | ||||||
|  |  | ||||||
| # Installshield output folder |  | ||||||
| [Ee]xpress/ |  | ||||||
|  |  | ||||||
| # DocProject is a documentation generator add-in |  | ||||||
| DocProject/buildhelp/ |  | ||||||
| DocProject/Help/*.HxT |  | ||||||
| DocProject/Help/*.HxC |  | ||||||
| DocProject/Help/*.hhc |  | ||||||
| DocProject/Help/*.hhk |  | ||||||
| DocProject/Help/*.hhp |  | ||||||
| DocProject/Help/Html2 |  | ||||||
| DocProject/Help/html |  | ||||||
|  |  | ||||||
| # Click-Once directory |  | ||||||
| publish/ |  | ||||||
|  |  | ||||||
| # Publish Web Output |  | ||||||
| *.[Pp]ublish.xml |  | ||||||
| *.azurePubxml |  | ||||||
| # Note: Comment the next line if you want to checkin your web deploy settings, |  | ||||||
| # but database connection strings (with potential passwords) will be unencrypted |  | ||||||
| *.pubxml |  | ||||||
| *.publishproj |  | ||||||
|  |  | ||||||
| # Microsoft Azure Web App publish settings. Comment the next line if you want to |  | ||||||
| # checkin your Azure Web App publish settings, but sensitive information contained |  | ||||||
| # in these scripts will be unencrypted |  | ||||||
| PublishScripts/ |  | ||||||
|  |  | ||||||
| # NuGet Packages |  | ||||||
| *.nupkg |  | ||||||
| # NuGet Symbol Packages |  | ||||||
| *.snupkg |  | ||||||
| # The packages folder can be ignored because of Package Restore |  | ||||||
| **/[Pp]ackages/* |  | ||||||
| # except build/, which is used as an MSBuild target. |  | ||||||
| !**/[Pp]ackages/build/ |  | ||||||
| # Uncomment if necessary however generally it will be regenerated when needed |  | ||||||
| #!**/[Pp]ackages/repositories.config |  | ||||||
| # NuGet v3's project.json files produces more ignorable files |  | ||||||
| *.nuget.props |  | ||||||
| *.nuget.targets |  | ||||||
|  |  | ||||||
| # Microsoft Azure Build Output |  | ||||||
| csx/ |  | ||||||
| *.build.csdef |  | ||||||
|  |  | ||||||
| # Microsoft Azure Emulator |  | ||||||
| ecf/ |  | ||||||
| rcf/ |  | ||||||
|  |  | ||||||
| # Windows Store app package directories and files |  | ||||||
| AppPackages/ |  | ||||||
| BundleArtifacts/ |  | ||||||
| Package.StoreAssociation.xml |  | ||||||
| _pkginfo.txt |  | ||||||
| *.appx |  | ||||||
| *.appxbundle |  | ||||||
| *.appxupload |  | ||||||
|  |  | ||||||
| # Visual Studio cache files |  | ||||||
| # files ending in .cache can be ignored |  | ||||||
| *.[Cc]ache |  | ||||||
| # but keep track of directories ending in .cache |  | ||||||
| !?*.[Cc]ache/ |  | ||||||
|  |  | ||||||
| # Others |  | ||||||
| ClientBin/ |  | ||||||
| ~$* |  | ||||||
| *~ |  | ||||||
| *.dbmdl |  | ||||||
| *.dbproj.schemaview |  | ||||||
| *.jfm |  | ||||||
| *.pfx |  | ||||||
| *.publishsettings |  | ||||||
| orleans.codegen.cs |  | ||||||
|  |  | ||||||
| # Including strong name files can present a security risk |  | ||||||
| # (https://github.com/github/gitignore/pull/2483#issue-259490424) |  | ||||||
| #*.snk |  | ||||||
|  |  | ||||||
| # Since there are multiple workflows, uncomment next line to ignore bower_components |  | ||||||
| # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) |  | ||||||
| #bower_components/ |  | ||||||
|  |  | ||||||
| # RIA/Silverlight projects |  | ||||||
| Generated_Code/ |  | ||||||
|  |  | ||||||
| # Backup & report files from converting an old project file |  | ||||||
| # to a newer Visual Studio version. Backup files are not needed, |  | ||||||
| # because we have git ;-) |  | ||||||
| _UpgradeReport_Files/ |  | ||||||
| Backup*/ |  | ||||||
| UpgradeLog*.XML |  | ||||||
| UpgradeLog*.htm |  | ||||||
| ServiceFabricBackup/ |  | ||||||
| *.rptproj.bak |  | ||||||
|  |  | ||||||
| # SQL Server files |  | ||||||
| *.mdf |  | ||||||
| *.ldf |  | ||||||
| *.ndf |  | ||||||
|  |  | ||||||
| # Business Intelligence projects |  | ||||||
| *.rdl.data |  | ||||||
| *.bim.layout |  | ||||||
| *.bim_*.settings |  | ||||||
| *.rptproj.rsuser |  | ||||||
| *- [Bb]ackup.rdl |  | ||||||
| *- [Bb]ackup ([0-9]).rdl |  | ||||||
| *- [Bb]ackup ([0-9][0-9]).rdl |  | ||||||
|  |  | ||||||
| # Microsoft Fakes |  | ||||||
| FakesAssemblies/ |  | ||||||
|  |  | ||||||
| # GhostDoc plugin setting file |  | ||||||
| *.GhostDoc.xml |  | ||||||
|  |  | ||||||
| # Node.js Tools for Visual Studio |  | ||||||
| .ntvs_analysis.dat |  | ||||||
| node_modules/ |  | ||||||
|  |  | ||||||
| # Visual Studio 6 build log |  | ||||||
| *.plg |  | ||||||
|  |  | ||||||
| # Visual Studio 6 workspace options file |  | ||||||
| *.opt |  | ||||||
|  |  | ||||||
| # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) |  | ||||||
| *.vbw |  | ||||||
|  |  | ||||||
| # Visual Studio LightSwitch build output |  | ||||||
| **/*.HTMLClient/GeneratedArtifacts |  | ||||||
| **/*.DesktopClient/GeneratedArtifacts |  | ||||||
| **/*.DesktopClient/ModelManifest.xml |  | ||||||
| **/*.Server/GeneratedArtifacts |  | ||||||
| **/*.Server/ModelManifest.xml |  | ||||||
| _Pvt_Extensions |  | ||||||
|  |  | ||||||
| # Paket dependency manager |  | ||||||
| .paket/paket.exe |  | ||||||
| paket-files/ |  | ||||||
|  |  | ||||||
| # FAKE - F# Make |  | ||||||
| .fake/ |  | ||||||
|  |  | ||||||
| # CodeRush personal settings |  | ||||||
| .cr/personal |  | ||||||
|  |  | ||||||
| # Python Tools for Visual Studio (PTVS) |  | ||||||
| __pycache__/ |  | ||||||
| *.pyc |  | ||||||
|  |  | ||||||
| # Cake - Uncomment if you are using it |  | ||||||
| # tools/** |  | ||||||
| # !tools/packages.config |  | ||||||
|  |  | ||||||
| # Tabs Studio |  | ||||||
| *.tss |  | ||||||
|  |  | ||||||
| # Telerik's JustMock configuration file |  | ||||||
| *.jmconfig |  | ||||||
|  |  | ||||||
| # BizTalk build output |  | ||||||
| *.btp.cs |  | ||||||
| *.btm.cs |  | ||||||
| *.odx.cs |  | ||||||
| *.xsd.cs |  | ||||||
|  |  | ||||||
| # OpenCover UI analysis results |  | ||||||
| OpenCover/ |  | ||||||
|  |  | ||||||
| # Azure Stream Analytics local run output |  | ||||||
| ASALocalRun/ |  | ||||||
|  |  | ||||||
| # MSBuild Binary and Structured Log |  | ||||||
| *.binlog |  | ||||||
|  |  | ||||||
| # NVidia Nsight GPU debugger configuration file |  | ||||||
| *.nvuser |  | ||||||
|  |  | ||||||
| # MFractors (Xamarin productivity tool) working folder |  | ||||||
| .mfractor/ |  | ||||||
|  |  | ||||||
| # Local History for Visual Studio |  | ||||||
| .localhistory/ |  | ||||||
|  |  | ||||||
| # BeatPulse healthcheck temp database |  | ||||||
| healthchecksdb |  | ||||||
|  |  | ||||||
| # Backup folder for Package Reference Convert tool in Visual Studio 2017 |  | ||||||
| MigrationBackup/ |  | ||||||
|  |  | ||||||
| # Ionide (cross platform F# VS Code tools) working folder |  | ||||||
| .ionide/ |  | ||||||
|  |  | ||||||
| # Fody - auto-generated XML schema |  | ||||||
| FodyWeavers.xsd |  | ||||||
|  |  | ||||||
| @@ -1,121 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk.Razor"> |  | ||||||
|  |  | ||||||
| 	<PropertyGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'"> |  | ||||||
| 		<DefineConstants>Pro</DefineConstants> |  | ||||||
| 	</PropertyGroup> |  | ||||||
| 	<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro'"> |  | ||||||
| 		 |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor.cs" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\Page\AllenBradleyCipTcpDebugPage.razor" Link="Pages\ABCIP\AllenBradleyCipTcpDebugPage.razor" /> |  | ||||||
| 		<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.AllenBradleyCip\ThingsGateway.Foundation.Adapter.AllenBradleyCip.csproj" /> |  | ||||||
|  |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsTcpDebugPage.razor.cs" Link="Pages\OmronFins\OmronFinsTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsUdpDebugPage.razor.cs" Link="Pages\OmronFins\OmronFinsUdpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsTcpDebugPage.razor" Link="Pages\OmronFins\OmronFinsTcpDebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Omron\Page\OmronFinsUdpDebugPage.razor" Link="Pages\OmronFins\OmronFinsUdpDebugPage.razor" /> |  | ||||||
| 		<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Omron\ThingsGateway.Foundation.Adapter.Omron.csproj" /> |  | ||||||
|  |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Secs\Page\SecsHsmsTcpDebugPage.razor.cs" Link="Pages\Secs\SecsHsmsTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Secs\Page\SecsHsmsTcpDebugPage.razor" Link="Pages\Secs\SecsHsmsTcpDebugPage.razor" /> |  | ||||||
| 		<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Secs\ThingsGateway.Foundation.Adapter.Secs.csproj" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.TS550\Page\TS550DebugPage.razor.cs" Link="Pages\TS550\TS550DebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.TS550\Page\TS550DebugPage.razor" Link="Pages\TS550\TS550DebugPage.razor" /> |  | ||||||
| 		<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.TS550\ThingsGateway.Foundation.Adapter.TS550.csproj" /> |  | ||||||
|  |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialDebugPage.razor.cs" Link="Pages\Vigor\VigorSerialDebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialOverTcpDebugPage.razor.cs" Link="Pages\Vigor\VigorSerialOverTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialDebugPage.razor" Link="Pages\Vigor\VigorSerialDebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\PluginPro\ThingsGateway.Plugin.Vigor\Page\VigorSerialOverTcpDebugPage.razor" Link="Pages\Vigor\VigorSerialOverTcpDebugPage.razor" /> |  | ||||||
| 		<ProjectReference Include="..\..\FoundationPro\ThingsGateway.Foundation.Adapter.Vigor\ThingsGateway.Foundation.Adapter.Vigor.csproj" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialDebugPage.razor.cs" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialDebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialOverTcpDebugPage.razor.cs" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialOverTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialDebugPage.razor" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialDebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\PluginProAF2021\ThingsGateway.Plugin.HZW_QTJC_01\Page\HZW_QTJC_01SerialOverTcpDebugPage.razor" Link="Pages\HZW_QTJC_01\HZW_QTJC_01SerialOverTcpDebugPage.razor" /> |  | ||||||
| 		<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Foundation.Adapter.HZW_QTJC_01\ThingsGateway.Foundation.Adapter.HZW_QTJC_01.csproj" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007DebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007DebugPage.razor" Link="Pages\DLT645\DLT645_2007DebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor.cs" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.DLT645\Page\DLT645_2007OverTcpDebugPage.razor" Link="Pages\DLT645\DLT645_2007OverTcpDebugPage.razor" /> |  | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuDebugPage.razor" Link="Pages\Modbus\ModbusRtuDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverTcpDebugPage.razor" Link="Pages\Modbus\ModbusRtuOverTcpDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverUdpDebugPage.razor.cs" Link="Pages\Modbus\ModbusRtuOverUdpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusRtuOverUdpDebugPage.razor" Link="Pages\Modbus\ModbusRtuOverUdpDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusSerialServerDebugPage.razor.cs" Link="Pages\Modbus\ModbusSerialServerDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusSerialServerDebugPage.razor" Link="Pages\Modbus\ModbusSerialServerDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDebugPage.razor" Link="Pages\Modbus\ModbusTcpDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDtuDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpDtuDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpDtuDebugPage.razor" Link="Pages\Modbus\ModbusTcpDtuDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpServerDebugPage.razor.cs" Link="Pages\Modbus\ModbusTcpServerDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusTcpServerDebugPage.razor" Link="Pages\Modbus\ModbusTcpServerDebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusUdpDebugPage.razor.cs" Link="Pages\Modbus\ModbusUdpDebugPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Modbus\Page\ModbusUdpDebugPage.razor" Link="Pages\Modbus\ModbusUdpDebugPage.razor" /> |  | ||||||
|  |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientDebugPage.razor.cs" Link="Pages\OPCDA\OPCDAClientDebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientPage.razor.cs" Link="Pages\OPCDA\OPCDAClientPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAImportVariable.razor.cs" Link="Pages\OPCDA\OPCDAImportVariable.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientDebugPage.razor" Link="Pages\OPCDA\OPCDAClientDebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAClientPage.razor" Link="Pages\OPCDA\OPCDAClientPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCDA\Page\OPCDAImportVariable.razor" Link="Pages\OPCDA\OPCDAImportVariable.razor" /> |  | ||||||
|  |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientDebugPage.razor" Link="Pages\OPCUA\OPCUAClientDebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientPage.razor" Link="Pages\OPCUA\OPCUAClientPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAImportVariable.razor" Link="Pages\OPCUA\OPCUAImportVariable.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientDebugPage.razor.cs" Link="Pages\OPCUA\OPCUAClientDebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAClientPage.razor.cs" Link="Pages\OPCUA\OPCUAClientPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.OPCUA\Page\OPCUAImportVariable.razor.cs" Link="Pages\OPCUA\OPCUAImportVariable.razor.cs" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1200DebugPage.razor" Link="Pages\Siemens\S7_1200DebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1500DebugPage.razor" Link="Pages\Siemens\S7_1500DebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200DebugPage.razor" Link="Pages\Siemens\S7_200DebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200SMARTDebugPage.razor" Link="Pages\Siemens\S7_200SMARTDebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_300DebugPage.razor" Link="Pages\Siemens\S7_300DebugPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_400DebugPage.razor" Link="Pages\Siemens\S7_400DebugPage.razor" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1200DebugPage.razor.cs" Link="Pages\Siemens\S7_1200DebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_1500DebugPage.razor.cs" Link="Pages\Siemens\S7_1500DebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200DebugPage.razor.cs" Link="Pages\Siemens\S7_200DebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_200SMARTDebugPage.razor.cs" Link="Pages\Siemens\S7_200SMARTDebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_300DebugPage.razor.cs" Link="Pages\Siemens\S7_300DebugPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Siemens\Page\S7_400DebugPage.razor.cs" Link="Pages\Siemens\S7_400DebugPage.razor.cs" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<Content Update="wwwroot\**"> |  | ||||||
| 			<CopyToOutputDirectory>Always</CopyToOutputDirectory> |  | ||||||
| 		</Content> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
| @@ -1,481 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.ComponentModel; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; |  | ||||||
| /// <summary> |  | ||||||
| /// DLT645_2007 |  | ||||||
| /// </summary> |  | ||||||
| public class DLT645_2007 : ReadWriteDevicesSerialSessionBase |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// DLT645_2007 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="serialSession"></param> |  | ||||||
|     public DLT645_2007(SerialSession serialSession) : base(serialSession) |  | ||||||
|     { |  | ||||||
|         ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big); |  | ||||||
|         RegisterByteLength = 2; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 增加FE FE FE FE的报文头部 |  | ||||||
|     /// </summary> |  | ||||||
|     [Description("前导符报文头")] |  | ||||||
|     public bool EnableFEHead { 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() |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         var str = """ |  | ||||||
|             查看附带文档或者相关资料,下面列举一下常见的数据标识地址  |  | ||||||
|              |  | ||||||
|             地址                       说明                     |  | ||||||
|             ----------------------------------------- |  | ||||||
|             02010100    A相电压 |  | ||||||
|             02020100    A相电流 |  | ||||||
|             02030000    瞬时总有功功率 |  | ||||||
|             00000000    (当前)组合有功总电能 |  | ||||||
|             00010000    (当前)正向有功总电能 |  | ||||||
|              |  | ||||||
|             """; |  | ||||||
|         return base.GetAddressDescription() + Environment.NewLine + str; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) |  | ||||||
|     { |  | ||||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Connect(cancellationToken); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult<byte[]>(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult<byte[]>(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void SetDataAdapter(object socketClient = null) |  | ||||||
|     { |  | ||||||
|         var dataHandleAdapter = new DLT645_2007DataHandleAdapter |  | ||||||
|         { |  | ||||||
|             EnableFEHead = EnableFEHead |  | ||||||
|         }; |  | ||||||
|         SerialSession.SetDataHandlingAdapter(dataHandleAdapter); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, string value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Connect(cancellationToken); |  | ||||||
|             Password ??= string.Empty; |  | ||||||
|             OperCode ??= string.Empty; |  | ||||||
|             if (Password.Length < 8) |  | ||||||
|                 Password = Password.PadLeft(8, '0'); |  | ||||||
|             if (OperCode.Length < 8) |  | ||||||
|                 OperCode = OperCode.PadLeft(8, '0'); |  | ||||||
|             var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes()); |  | ||||||
|             string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             Password ??= string.Empty; |  | ||||||
|             OperCode ??= string.Empty; |  | ||||||
|             if (Password.Length < 8) |  | ||||||
|                 Password = Password.PadLeft(8, '0'); |  | ||||||
|             if (OperCode.Length < 8) |  | ||||||
|                 OperCode = OperCode.PadLeft(8, '0'); |  | ||||||
|             var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes()); |  | ||||||
|             string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     #region 其他方法 |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 广播校时 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="dateTime"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Connect(cancellationToken); |  | ||||||
|             string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}"; |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().ToArray(), "999999999999".ByHexStringToBytes()); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 SerialSession.Send(commandResult.Content); |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 冻结 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="dateTime"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             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().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray()); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 读取通信地址 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes()); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 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 new OperResult<string>(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult<string>(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 修改波特率 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="baudRate"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             byte baudRateByte; |  | ||||||
|             switch (baudRate) |  | ||||||
|             { |  | ||||||
|                 case 600: baudRateByte = 0x02; break; |  | ||||||
|                 case 1200: baudRateByte = 0x04; break; |  | ||||||
|                 case 2400: baudRateByte = 0x08; break; |  | ||||||
|                 case 4800: baudRateByte = 0x10; break; |  | ||||||
|                 case 9600: baudRateByte = 0x20; break; |  | ||||||
|                 case 19200: baudRateByte = 0x40; break; |  | ||||||
|                 default: return new OperResult<string>($"不支持此波特率:{baudRate}"); |  | ||||||
|             } |  | ||||||
|             if (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, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 更新通信地址 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="station"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             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, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(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="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|  |  | ||||||
|             if (Station.IsNullOrEmpty()) Station = string.Empty; |  | ||||||
|             if (Station.Length < 12) Station = Station.PadLeft(12, '0'); |  | ||||||
|             string str = $"04000C{(level + 1):D2}"; |  | ||||||
|  |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword, |  | ||||||
|                 str.ByHexStringToBytes().Reverse().ToArray() |  | ||||||
|                 .SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray()) |  | ||||||
|                 .SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray()) |  | ||||||
|                 , Station.ByHexStringToBytes().Reverse().ToArray()); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     #endregion |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,481 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.ComponentModel; |  | ||||||
|  |  | ||||||
| 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(TcpClient tcpClient) : base(tcpClient) |  | ||||||
|     { |  | ||||||
|         ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big); |  | ||||||
|         RegisterByteLength = 2; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 增加FE FE FE FE的报文头部 |  | ||||||
|     /// </summary> |  | ||||||
|     [Description("前导符报文头")] |  | ||||||
|     public bool EnableFEHead { 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() |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         var str = """ |  | ||||||
|             查看附带文档或者相关资料,下面列举一下常见的数据标识地址  |  | ||||||
|              |  | ||||||
|             地址                       说明                     |  | ||||||
|             ----------------------------------------- |  | ||||||
|             02010100    A相电压 |  | ||||||
|             02020100    A相电流 |  | ||||||
|             02030000    瞬时总有功功率 |  | ||||||
|             00000000    (当前)组合有功总电能 |  | ||||||
|             00010000    (当前)正向有功总电能 |  | ||||||
|              |  | ||||||
|             """; |  | ||||||
|         return base.GetAddressDescription() + Environment.NewLine + str; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) |  | ||||||
|     { |  | ||||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Connect(cancellationToken); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult<byte[]>(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Read, Station); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult<byte[]>(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void SetDataAdapter(object socketClient = null) |  | ||||||
|     { |  | ||||||
|         var dataHandleAdapter = new DLT645_2007DataHandleAdapter |  | ||||||
|         { |  | ||||||
|             EnableFEHead = EnableFEHead |  | ||||||
|         }; |  | ||||||
|         TcpClient.SetDataHandlingAdapter(dataHandleAdapter); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, string value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Connect(cancellationToken); |  | ||||||
|             Password ??= string.Empty; |  | ||||||
|             OperCode ??= string.Empty; |  | ||||||
|             if (Password.Length < 8) |  | ||||||
|                 Password = Password.PadLeft(8, '0'); |  | ||||||
|             if (OperCode.Length < 8) |  | ||||||
|                 OperCode = OperCode.PadLeft(8, '0'); |  | ||||||
|             var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes()); |  | ||||||
|             string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) => Write(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             Password ??= string.Empty; |  | ||||||
|             OperCode ??= string.Empty; |  | ||||||
|             if (Password.Length < 8) |  | ||||||
|                 Password = Password.PadLeft(8, '0'); |  | ||||||
|             if (OperCode.Length < 8) |  | ||||||
|                 OperCode = OperCode.PadLeft(8, '0'); |  | ||||||
|             var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes()); |  | ||||||
|             string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command(address, (byte)ControlCode.Write, Station, data, strArray); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 return (MessageBase)result.RequestInfo; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, double value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, float value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, long value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, short value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, int value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) => WriteAsync(address, value.ToString(), cancellationToken); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     #region 其他方法 |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 广播校时 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="dateTime"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public OperResult BroadcastTime(DateTime dateTime, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Connect(cancellationToken); |  | ||||||
|             string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}"; |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().Reverse().ToArray(), "999999999999".ByHexStringToBytes()); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 TcpClient.Send(commandResult.Content); |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 冻结 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="dateTime"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             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, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 读取通信地址 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes()); |  | ||||||
|             if (commandResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); |  | ||||||
|                 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 new OperResult<string>(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult<string>(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 修改波特率 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="baudRate"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             byte baudRateByte; |  | ||||||
|             switch (baudRate) |  | ||||||
|             { |  | ||||||
|                 case 600: baudRateByte = 0x02; break; |  | ||||||
|                 case 1200: baudRateByte = 0x04; break; |  | ||||||
|                 case 2400: baudRateByte = 0x08; break; |  | ||||||
|                 case 4800: baudRateByte = 0x10; break; |  | ||||||
|                 case 9600: baudRateByte = 0x20; break; |  | ||||||
|                 case 19200: baudRateByte = 0x40; break; |  | ||||||
|                 default: return new OperResult<string>($"不支持此波特率:{baudRate}"); |  | ||||||
|             } |  | ||||||
|             if (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, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 更新通信地址 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="station"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|             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, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(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="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await ConnectAsync(cancellationToken); |  | ||||||
|  |  | ||||||
|             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, cancellationToken); |  | ||||||
|                 var result1 = ((MessageBase)result.RequestInfo); |  | ||||||
|                 if (result1.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return new OperResult(commandResult); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<string>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     #endregion |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,442 +0,0 @@ | |||||||
| <?xml version="1.0"?> |  | ||||||
| <doc> |  | ||||||
|     <assembly> |  | ||||||
|         <name>ThingsGateway.Foundation.Adapter.DLT645</name> |  | ||||||
|     </assembly> |  | ||||||
|     <members> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DataInfo"> |  | ||||||
|             <summary> |  | ||||||
|             解析参数 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.ByteLength"> |  | ||||||
|             <summary> |  | ||||||
|             解析长度 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.Digtal"> |  | ||||||
|             <summary> |  | ||||||
|             小数位 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DataInfo.IsSigned"> |  | ||||||
|             <summary> |  | ||||||
|             有符号解析 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645Helper.GetDataInfos(System.Byte[])"> |  | ||||||
|             <summary> |  | ||||||
|             获取返回的解析信息 |  | ||||||
|             </summary> |  | ||||||
|             <param name="buffer"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645Helper.GetDLT645_2007Command(System.String,System.Int32,System.Byte,System.String,System.Byte[],System.String[])"> |  | ||||||
|             <summary> |  | ||||||
|             获取DLT645报文 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.#ctor(ThingsGateway.Foundation.Serial.SerialSession)"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007 |  | ||||||
|             </summary> |  | ||||||
|             <param name="serialSession"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.EnableFEHead"> |  | ||||||
|             <summary> |  | ||||||
|             增加FE FE FE FE的报文头部 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.OperCode"> |  | ||||||
|             <summary> |  | ||||||
|             写入需操作员代码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.Password"> |  | ||||||
|             <summary> |  | ||||||
|             写入密码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.Station"> |  | ||||||
|             <summary> |  | ||||||
|             通讯地址BCD码,一般应该是12个字符 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.GetAddressDescription"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.SetDataAdapter"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Byte,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Double,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Single,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int64,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt64,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.UInt16,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int16,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.BroadcastTime(System.DateTime,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             广播校时 |  | ||||||
|             </summary> |  | ||||||
|             <param name="dateTime"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.FreezeAsync(System.DateTime,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             冻结 |  | ||||||
|             </summary> |  | ||||||
|             <param name="dateTime"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.ReadDeviceStationAsync(System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取通信地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             修改波特率 |  | ||||||
|             </summary> |  | ||||||
|             <param name="baudRate"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             更新通信地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="station"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             修改密码 |  | ||||||
|             </summary> |  | ||||||
|             <param name="level"></param> |  | ||||||
|             <param name="oldPassword"></param> |  | ||||||
|             <param name="newPassword"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.ControlCode"> |  | ||||||
|             <summary> |  | ||||||
|             控制码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Read"> |  | ||||||
|             <summary> |  | ||||||
|             读数据 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.ReadSub"> |  | ||||||
|             <summary> |  | ||||||
|             读后续数据 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.ReadStation"> |  | ||||||
|             <summary> |  | ||||||
|             读站号 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Write"> |  | ||||||
|             <summary> |  | ||||||
|             写数据 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WriteStation"> |  | ||||||
|             <summary> |  | ||||||
|             写站号 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.BroadcastTime"> |  | ||||||
|             <summary> |  | ||||||
|             广播校时 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.Freeze"> |  | ||||||
|             <summary> |  | ||||||
|             冻结 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WriteBaudRate"> |  | ||||||
|             <summary> |  | ||||||
|             更新波特率 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.DLT645.ControlCode.WritePassword"> |  | ||||||
|             <summary> |  | ||||||
|             更新密码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007Address |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor(System.String,System.UInt16)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.#ctor(System.String,System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.DataId"> |  | ||||||
|             <summary> |  | ||||||
|             数据标识 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Reverse"> |  | ||||||
|             <summary> |  | ||||||
|             反转解析 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Station"> |  | ||||||
|             <summary> |  | ||||||
|             站号信息 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.Parse(System.String,System.Int32)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.ParseFrom(System.String,System.Int32)"> |  | ||||||
|             <summary> |  | ||||||
|             解析地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="address"></param> |  | ||||||
|             <param name="length"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007Address.ToString"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.#ctor(ThingsGateway.Foundation.EndianType)"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToDouble(System.Byte[],System.Int32)"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645协议转换double |  | ||||||
|             </summary> |  | ||||||
|             <param name="buffer">带数据项标识</param> |  | ||||||
|             <param name="offset"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[],System.Int32,System.Int32)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007DataHandleAdapter |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.EnableFEHead"> |  | ||||||
|             <summary> |  | ||||||
|             增加FE FE FE FE的报文头部 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.PackCommand(System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.GetInstance"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message,System.Byte[],System.Byte[],System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.#ctor(ThingsGateway.Foundation.TcpClient)"> |  | ||||||
|             <summary> |  | ||||||
|             DLT645_2007 |  | ||||||
|             </summary> |  | ||||||
|             <param name="tcpClient"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.EnableFEHead"> |  | ||||||
|             <summary> |  | ||||||
|             增加FE FE FE FE的报文头部 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.OperCode"> |  | ||||||
|             <summary> |  | ||||||
|             写入需操作员代码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.Password"> |  | ||||||
|             <summary> |  | ||||||
|             写入密码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.Station"> |  | ||||||
|             <summary> |  | ||||||
|             通讯地址BCD码,一般应该是12个字符 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.GetAddressDescription"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.SetDataAdapter"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Byte,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Double,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Single,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int64,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt64,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.UInt16,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int16,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.BroadcastTime(System.DateTime,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             广播校时 |  | ||||||
|             </summary> |  | ||||||
|             <param name="dateTime"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.FreezeAsync(System.DateTime,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             冻结 |  | ||||||
|             </summary> |  | ||||||
|             <param name="dateTime"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.ReadDeviceStationAsync(System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取通信地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteBaudRateAsync(System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             修改波特率 |  | ||||||
|             </summary> |  | ||||||
|             <param name="baudRate"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WriteDeviceStationAsync(System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             更新通信地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="station"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.WritePasswordAsync(System.Byte,System.String,System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             修改密码 |  | ||||||
|             </summary> |  | ||||||
|             <param name="level"></param> |  | ||||||
|             <param name="oldPassword"></param> |  | ||||||
|             <param name="newPassword"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.HeadBytesLength"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.CheckHeadBytes(System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message.SendBytesThen"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|     </members> |  | ||||||
| </doc> |  | ||||||
| @@ -1,421 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Collections.Generic; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.Bool; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端 |  | ||||||
|     /// </summary> |  | ||||||
|     public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SerialSession, OperResult> WriteData; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 继电器 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new(); |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 开关输入 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new(); |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 输入寄存器 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new(); |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 保持寄存器 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public ModbusSerialServer(SerialSession serialSession) : base(serialSession) |  | ||||||
|     { |  | ||||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); |  | ||||||
|         RegisterByteLength = 2; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 多站点 |  | ||||||
|     /// </summary> |  | ||||||
|     public bool MulStation { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 默认站点 |  | ||||||
|     /// </summary> |  | ||||||
|     public byte Station { get; set; } = 1; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void Dispose() |  | ||||||
|     { |  | ||||||
|         foreach (var item in ModbusServer01ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         foreach (var item in ModbusServer02ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         foreach (var item in ModbusServer03ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         foreach (var item in ModbusServer04ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         ModbusServer01ByteBlocks.Clear(); |  | ||||||
|         ModbusServer02ByteBlocks.Clear(); |  | ||||||
|         ModbusServer03ByteBlocks.Clear(); |  | ||||||
|         ModbusServer04ByteBlocks.Clear(); |  | ||||||
|         base.Dispose(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string GetAddressDescription() |  | ||||||
|     { |  | ||||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) |  | ||||||
|     { |  | ||||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         ModbusAddress mAddress; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             mAddress = ModbusAddress.ParseFrom(address, Station); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|         if (MulStation) |  | ||||||
|         { |  | ||||||
|             Init(mAddress); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (Station != mAddress.Station) |  | ||||||
|             { |  | ||||||
|                 return new OperResult<byte[]>("地址错误"); |  | ||||||
|             } |  | ||||||
|             Init(mAddress); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station]; |  | ||||||
|         int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength; |  | ||||||
|         switch (mAddress.ReadFunction) |  | ||||||
|         { |  | ||||||
|             case 1: |  | ||||||
|                 byte[] bytes0 = new byte[len]; |  | ||||||
|                 ModbusServer01ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer01ByteBlock.Read(bytes0); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes0); |  | ||||||
|             case 2: |  | ||||||
|                 byte[] bytes1 = new byte[len]; |  | ||||||
|                 ModbusServer02ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer02ByteBlock.Read(bytes1); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes1); |  | ||||||
|             case 3: |  | ||||||
|  |  | ||||||
|                 byte[] bytes3 = new byte[len]; |  | ||||||
|                 ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer03ByteBlock.Read(bytes3); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes3); |  | ||||||
|             case 4: |  | ||||||
|                 byte[] bytes4 = new byte[len]; |  | ||||||
|                 ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer04ByteBlock.Read(bytes4); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes4); |  | ||||||
|         } |  | ||||||
|         return new OperResult<byte[]>("功能码错误"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return Task.FromResult(Read(address, length)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void SetDataAdapter(object socketClient) |  | ||||||
|     { |  | ||||||
|         ModbusSerialServerDataHandleAdapter dataHandleAdapter = new(); |  | ||||||
|         dataHandleAdapter.CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout); |  | ||||||
|         SerialSession.SetDataHandlingAdapter(dataHandleAdapter); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         ModbusAddress mAddress; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             mAddress = ModbusAddress.ParseFrom(address, Station); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult(ex); |  | ||||||
|         } |  | ||||||
|         if (MulStation) |  | ||||||
|         { |  | ||||||
|             Init(mAddress); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (Station != mAddress.Station) |  | ||||||
|             { |  | ||||||
|                 return new OperResult("地址错误"); |  | ||||||
|             } |  | ||||||
|             Init(mAddress); |  | ||||||
|         } |  | ||||||
|         var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station]; |  | ||||||
|         switch (mAddress.ReadFunction) |  | ||||||
|         { |  | ||||||
|             case 3: |  | ||||||
|                 ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer03ByteBlock.Write(value); |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|             case 4: |  | ||||||
|                 ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer04ByteBlock.Write(value); |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|         } |  | ||||||
|         return new OperResult("功能码错误"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         ModbusAddress mAddress; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             mAddress = ModbusAddress.ParseFrom(address, Station); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return (new OperResult(ex)); |  | ||||||
|         } |  | ||||||
|         if (MulStation) |  | ||||||
|         { |  | ||||||
|             Init(mAddress); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (Station != mAddress.Station) |  | ||||||
|             { |  | ||||||
|                 return (new OperResult("地址错误")); |  | ||||||
|             } |  | ||||||
|             Init(mAddress); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station]; |  | ||||||
|         switch (mAddress.ReadFunction) |  | ||||||
|         { |  | ||||||
|             case 1: |  | ||||||
|                 ModbusServer01ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer01ByteBlock.Write(value.BoolArrayToByte()); |  | ||||||
|                 return (OperResult.CreateSuccessResult()); |  | ||||||
|             case 2: |  | ||||||
|                 ModbusServer02ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer02ByteBlock.Write(value.BoolArrayToByte()); |  | ||||||
|                 return (OperResult.CreateSuccessResult()); |  | ||||||
|         } |  | ||||||
|         return new OperResult("功能码错误"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return Task.FromResult(Write(address, value)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return Task.FromResult(Write(address, value)); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Received(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             //接收外部报文 |  | ||||||
|             if (requestInfo is ModbusSerialServerMessage modbusServerMessage) |  | ||||||
|             { |  | ||||||
|                 if (modbusServerMessage.CurModbusAddress == null) |  | ||||||
|                 { |  | ||||||
|                     return;//无法解析直接返回 |  | ||||||
|                 } |  | ||||||
|                 if (!modbusServerMessage.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return;//无法解析直接返回 |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取 |  | ||||||
|                 { |  | ||||||
|                     var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.Length); |  | ||||||
|                     if (data.IsSuccess) |  | ||||||
|                     { |  | ||||||
|                         var coreData = data.Content; |  | ||||||
|                         if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2) |  | ||||||
|                         { |  | ||||||
|                             coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling(modbusServerMessage.Length / 8.0)); |  | ||||||
|                         } |  | ||||||
|                         var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 2).SpliceArray(new byte[] { (byte)coreData.Length }, coreData); |  | ||||||
|                         SerialSession.Send(sendData); |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         WriteError(SerialSession, modbusServerMessage);//返回错误码 |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 else//写入 |  | ||||||
|                 { |  | ||||||
|                     var coreData = modbusServerMessage.Content; |  | ||||||
|                     if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2) |  | ||||||
|                     { |  | ||||||
|                         //写入继电器 |  | ||||||
|                         if (WriteData != null) |  | ||||||
|                         { |  | ||||||
|                             // 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端 |  | ||||||
|                             if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length)); |  | ||||||
|                                 if (result.IsSuccess) |  | ||||||
|                                 { |  | ||||||
|                                     WriteSuccess03(SerialSession, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     WriteError(SerialSession, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(SerialSession, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             //写入内存区 |  | ||||||
|                             var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length)); |  | ||||||
|                             if (result.IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 WriteSuccess03(SerialSession, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(SerialSession, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         //写入寄存器 |  | ||||||
|                         if (WriteData != null) |  | ||||||
|                         { |  | ||||||
|  |  | ||||||
|                             if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, SerialSession)).IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData); |  | ||||||
|                                 if (result.IsSuccess) |  | ||||||
|                                 { |  | ||||||
|                                     WriteSuccess03(SerialSession, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     WriteError(SerialSession, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(SerialSession, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData); |  | ||||||
|                             if (result.IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 WriteSuccess03(SerialSession, modbusServerMessage); |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(SerialSession, modbusServerMessage); |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             Logger.LogError(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         //返回错误码 |  | ||||||
|         static void WriteError(SerialSession SerialSession, ModbusSerialServerMessage modbusServerMessage) |  | ||||||
|         { |  | ||||||
|             var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 2) |  | ||||||
| .SpliceArray(new byte[] { (byte)1 });//01 lllegal function |  | ||||||
|             sendData[1] = (byte)(sendData[1] + 128); |  | ||||||
|             SerialSession.Send(sendData); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private static void WriteSuccess03(SerialSession SerialSession, ModbusSerialServerMessage modbusServerMessage) |  | ||||||
|     { |  | ||||||
|         var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 6); |  | ||||||
|         SerialSession.Send(sendData); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void Init(ModbusAddress mAddress) |  | ||||||
|     { |  | ||||||
|         if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|         if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|         if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|         if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,441 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.ComponentModel; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.Bool; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusTcpServer : ReadWriteDevicesTcpServerBase |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端 |  | ||||||
|     /// </summary> |  | ||||||
|     public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, SocketClient, OperResult> WriteData; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 继电器 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks = new(); |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 开关输入 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer02ByteBlocks = new(); |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 输入寄存器 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer03ByteBlocks = new(); |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 保持寄存器 |  | ||||||
|     /// </summary> |  | ||||||
|     private ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public ModbusTcpServer(TcpService tcpService) : base(tcpService) |  | ||||||
|     { |  | ||||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); |  | ||||||
|         RegisterByteLength = 2; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 多站点 |  | ||||||
|     /// </summary> |  | ||||||
|     [Description("多站点")] |  | ||||||
|     public bool MulStation { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 默认站点 |  | ||||||
|     /// </summary> |  | ||||||
|     [Description("默认站点")] |  | ||||||
|     public byte Station { get; set; } = 1; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void Dispose() |  | ||||||
|     { |  | ||||||
|         foreach (var item in ModbusServer01ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         foreach (var item in ModbusServer02ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         foreach (var item in ModbusServer03ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         foreach (var item in ModbusServer04ByteBlocks) |  | ||||||
|         { |  | ||||||
|             item.Value.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         ModbusServer01ByteBlocks.Clear(); |  | ||||||
|         ModbusServer02ByteBlocks.Clear(); |  | ||||||
|         ModbusServer03ByteBlocks.Clear(); |  | ||||||
|         ModbusServer04ByteBlocks.Clear(); |  | ||||||
|         base.Dispose(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string GetAddressDescription() |  | ||||||
|     { |  | ||||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) |  | ||||||
|     { |  | ||||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         ModbusAddress mAddress; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             mAddress = ModbusAddress.ParseFrom(address, Station); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<byte[]>(ex); |  | ||||||
|         } |  | ||||||
|         if (MulStation) |  | ||||||
|         { |  | ||||||
|             Init(mAddress); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (Station != mAddress.Station) |  | ||||||
|             { |  | ||||||
|                 return new OperResult<byte[]>("地址错误"); |  | ||||||
|             } |  | ||||||
|             Init(mAddress); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station]; |  | ||||||
|         int len = mAddress.ReadFunction == 2 || mAddress.ReadFunction == 1 ? length : length * RegisterByteLength; |  | ||||||
|         switch (mAddress.ReadFunction) |  | ||||||
|         { |  | ||||||
|             case 1: |  | ||||||
|                 byte[] bytes0 = new byte[len]; |  | ||||||
|                 ModbusServer01ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer01ByteBlock.Read(bytes0); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes0); |  | ||||||
|             case 2: |  | ||||||
|                 byte[] bytes1 = new byte[len]; |  | ||||||
|                 ModbusServer02ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer02ByteBlock.Read(bytes1); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes1); |  | ||||||
|             case 3: |  | ||||||
|  |  | ||||||
|                 byte[] bytes3 = new byte[len]; |  | ||||||
|                 ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer03ByteBlock.Read(bytes3); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes3); |  | ||||||
|             case 4: |  | ||||||
|                 byte[] bytes4 = new byte[len]; |  | ||||||
|                 ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer04ByteBlock.Read(bytes4); |  | ||||||
|                 return OperResult.CreateSuccessResult(bytes4); |  | ||||||
|         } |  | ||||||
|         return new OperResult<byte[]>("功能码错误"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return Task.FromResult(Read(address, length)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void SetDataAdapter(object socketClient) |  | ||||||
|     { |  | ||||||
|         if (socketClient is SocketClient client) |  | ||||||
|         { |  | ||||||
|             ModbusTcpServerDataHandleAdapter dataHandleAdapter = new(); |  | ||||||
|             dataHandleAdapter.CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout); |  | ||||||
|             client.SetDataHandlingAdapter(dataHandleAdapter); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             foreach (var item in TcpService.GetClients()) |  | ||||||
|             { |  | ||||||
|                 ModbusTcpDataHandleAdapter dataHandleAdapter = new() |  | ||||||
|                 { |  | ||||||
|                     CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) |  | ||||||
|                 }; |  | ||||||
|                 item.SetDataHandlingAdapter(dataHandleAdapter); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         ModbusAddress mAddress; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             mAddress = ModbusAddress.ParseFrom(address, Station); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult(ex); |  | ||||||
|         } |  | ||||||
|         if (MulStation) |  | ||||||
|         { |  | ||||||
|             Init(mAddress); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (Station != mAddress.Station) |  | ||||||
|             { |  | ||||||
|                 return new OperResult("地址错误"); |  | ||||||
|             } |  | ||||||
|             Init(mAddress); |  | ||||||
|         } |  | ||||||
|         var ModbusServer03ByteBlock = ModbusServer03ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer04ByteBlock = ModbusServer04ByteBlocks[mAddress.Station]; |  | ||||||
|         switch (mAddress.ReadFunction) |  | ||||||
|         { |  | ||||||
|             case 3: |  | ||||||
|                 ModbusServer03ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer03ByteBlock.Write(value); |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|             case 4: |  | ||||||
|                 ModbusServer04ByteBlock.Pos = mAddress.AddressStart * RegisterByteLength; |  | ||||||
|                 ModbusServer04ByteBlock.Write(value); |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|         } |  | ||||||
|         return new OperResult("功能码错误"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         ModbusAddress mAddress; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             mAddress = ModbusAddress.ParseFrom(address, Station); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return (new OperResult(ex)); |  | ||||||
|         } |  | ||||||
|         if (MulStation) |  | ||||||
|         { |  | ||||||
|             Init(mAddress); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (Station != mAddress.Station) |  | ||||||
|             { |  | ||||||
|                 return (new OperResult("地址错误")); |  | ||||||
|             } |  | ||||||
|             Init(mAddress); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         var ModbusServer01ByteBlock = ModbusServer01ByteBlocks[mAddress.Station]; |  | ||||||
|         var ModbusServer02ByteBlock = ModbusServer02ByteBlocks[mAddress.Station]; |  | ||||||
|         switch (mAddress.ReadFunction) |  | ||||||
|         { |  | ||||||
|             case 1: |  | ||||||
|                 ModbusServer01ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer01ByteBlock.Write(value.BoolArrayToByte()); |  | ||||||
|                 return (OperResult.CreateSuccessResult()); |  | ||||||
|             case 2: |  | ||||||
|                 ModbusServer02ByteBlock.Pos = mAddress.AddressStart; |  | ||||||
|                 ModbusServer02ByteBlock.Write(value.BoolArrayToByte()); |  | ||||||
|                 return (OperResult.CreateSuccessResult()); |  | ||||||
|         } |  | ||||||
|         return new OperResult("功能码错误"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return Task.FromResult(Write(address, value)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return Task.FromResult(Write(address, value)); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Received(SocketClient client, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             //接收外部报文 |  | ||||||
|             if (requestInfo is ModbusTcpServerMessage modbusServerMessage) |  | ||||||
|             { |  | ||||||
|                 if (modbusServerMessage.CurModbusAddress == null) |  | ||||||
|                 { |  | ||||||
|                     return;//无法解析直接返回 |  | ||||||
|                 } |  | ||||||
|                 if (!modbusServerMessage.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     return;//无法解析直接返回 |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (modbusServerMessage.CurModbusAddress.WriteFunction == 0)//读取 |  | ||||||
|                 { |  | ||||||
|                     var data = Read(modbusServerMessage.CurModbusAddress.ToString(), modbusServerMessage.Length); |  | ||||||
|                     if (data.IsSuccess) |  | ||||||
|                     { |  | ||||||
|                         var coreData = data.Content; |  | ||||||
|                         if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2) |  | ||||||
|                         { |  | ||||||
|                             coreData = data.Content.Select(m => m > 0).ToArray().BoolArrayToByte().SelectMiddle(0, (int)Math.Ceiling(modbusServerMessage.Length / 8.0)); |  | ||||||
|                         } |  | ||||||
|                         var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8).SpliceArray(new byte[] { (byte)coreData.Length }, coreData); |  | ||||||
|                         sendData[5] = (byte)(sendData.Length - 6); |  | ||||||
|                         client.Send(sendData); |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         WriteError(client, modbusServerMessage);//返回错误码 |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 else//写入 |  | ||||||
|                 { |  | ||||||
|                     var coreData = modbusServerMessage.Content; |  | ||||||
|                     if (modbusServerMessage.CurModbusAddress.ReadFunction == 1 || modbusServerMessage.CurModbusAddress.ReadFunction == 2) |  | ||||||
|                     { |  | ||||||
|                         //写入继电器 |  | ||||||
|                         if (WriteData != null) |  | ||||||
|                         { |  | ||||||
|                             // 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端 |  | ||||||
|                             if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length)); |  | ||||||
|                                 if (result.IsSuccess) |  | ||||||
|                                 { |  | ||||||
|                                     WriteSuccess03(client, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     WriteError(client, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(client, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             //写入内存区 |  | ||||||
|                             var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length)); |  | ||||||
|                             if (result.IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 WriteSuccess03(client, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(client, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         //写入寄存器 |  | ||||||
|                         if (WriteData != null) |  | ||||||
|                         { |  | ||||||
|  |  | ||||||
|                             if ((WriteData(modbusServerMessage.CurModbusAddress, modbusServerMessage.Content, ThingsGatewayBitConverter, client)).IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData); |  | ||||||
|                                 if (result.IsSuccess) |  | ||||||
|                                 { |  | ||||||
|                                     WriteSuccess03(client, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     WriteError(client, modbusServerMessage); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(client, modbusServerMessage); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             var result = Write(modbusServerMessage.CurModbusAddress.ToString(), coreData); |  | ||||||
|                             if (result.IsSuccess) |  | ||||||
|                             { |  | ||||||
|                                 WriteSuccess03(client, modbusServerMessage); |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 WriteError(client, modbusServerMessage); |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             Logger.LogError(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         //返回错误码 |  | ||||||
|         static void WriteError(SocketClient client, ModbusTcpServerMessage modbusServerMessage) |  | ||||||
|         { |  | ||||||
|             var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 8) |  | ||||||
| .SpliceArray(new byte[] { (byte)1 });//01 lllegal function |  | ||||||
|             sendData[5] = (byte)(sendData.Length - 6); |  | ||||||
|             sendData[7] = (byte)(sendData[7] + 128); |  | ||||||
|             client.Send(sendData); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private static void WriteSuccess03(SocketClient client, ModbusTcpServerMessage modbusServerMessage) |  | ||||||
|     { |  | ||||||
|         var sendData = modbusServerMessage.ReceivedBytes.SelectMiddle(0, 12); |  | ||||||
|         sendData[5] = (byte)(sendData.Length - 6); |  | ||||||
|         client.Send(sendData); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void Init(ModbusAddress mAddress) |  | ||||||
|     { |  | ||||||
|         if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|         if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|         if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|         if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128))) |  | ||||||
|             ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
| @@ -1,579 +0,0 @@ | |||||||
| <?xml version="1.0"?> |  | ||||||
| <doc> |  | ||||||
|     <assembly> |  | ||||||
|         <name>ThingsGateway.Foundation.Adapter.OPCDA</name> |  | ||||||
|     </assembly> |  | ||||||
|     <members> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.CollectionExtensions.RemoveWhere``1(System.Collections.Generic.ICollection{``0},System.Func{``0,System.Boolean})"> |  | ||||||
|             <summary> |  | ||||||
|             移除符合条件的元素 |  | ||||||
|             </summary> |  | ||||||
|             <typeparam name="T"></typeparam> |  | ||||||
|             <param name="this"></param> |  | ||||||
|             <param name="where"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.LOCALE_SYSTEM_DEFAULT"> |  | ||||||
|             <summary> |  | ||||||
|             The WIN32 system default locale. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.LOCALE_USER_DEFAULT"> |  | ||||||
|             <summary> |  | ||||||
|             The WIN32 user default locale. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.CreateInstance(System.Guid,System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             创建一个COM服务器的实例。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.GetSystemMessage(System.Int32)"> |  | ||||||
|             <summary> |  | ||||||
|             指定错误消息文本检索系统。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.InitializeSecurity"> |  | ||||||
|             <summary> |  | ||||||
|             初始化COM安全。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.ReadClasses(ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCEnumGUID)"> |  | ||||||
|             <summary> |  | ||||||
|             从枚举器读取guid。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.ReadClasses(ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumGUID)"> |  | ||||||
|             <summary> |  | ||||||
|             从枚举器读取guid。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Comn.ComInterop.RealseComServer(System.Object)"> |  | ||||||
|             <summary> |  | ||||||
|             释放 COM 对象 |  | ||||||
|             </summary> |  | ||||||
|             <param name="m_server"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCDA.Comn.Convert.FILETIME_BaseTime"> |  | ||||||
|             <summary> |  | ||||||
|             windows的filetime是从1601-1-1 00:00:00开始的,datetime是从1-1-1 00:00:00开始的 |  | ||||||
|             datetime和filetime的滴答单位都是100ns(100纳秒,千万分之一秒),所以转换时只需要考虑开始时间即可 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OnDataChangedHandler"> |  | ||||||
|             <summary> |  | ||||||
|             值变化 |  | ||||||
|             </summary> |  | ||||||
|             <param name="opcItems"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OnReadCompletedHandler"> |  | ||||||
|             <summary> |  | ||||||
|             读取 |  | ||||||
|             </summary> |  | ||||||
|             <param name="opcItems"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OnWriteCompletedHandler"> |  | ||||||
|             <summary> |  | ||||||
|             写入 |  | ||||||
|             </summary> |  | ||||||
|             <param name="opcItems"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult"> |  | ||||||
|             <summary> |  | ||||||
|             返回结果 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.Name"> |  | ||||||
|             <summary> |  | ||||||
|             ID |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.Quality"> |  | ||||||
|             <summary> |  | ||||||
|             Quality |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.TimeStamp"> |  | ||||||
|             <summary> |  | ||||||
|             TimeStamp |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ItemReadResult.Value"> |  | ||||||
|             <summary> |  | ||||||
|             Value |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcGroup.InitIoInterfaces(System.Object)"> |  | ||||||
|             <summary> |  | ||||||
|             建立连接 |  | ||||||
|             </summary> |  | ||||||
|             <param name="handle"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcGroup.ReadAsync"> |  | ||||||
|             <summary> |  | ||||||
|             组读取 |  | ||||||
|             </summary> |  | ||||||
|             <exception cref="T:System.Runtime.InteropServices.ExternalException"></exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem"> |  | ||||||
|             <summary> |  | ||||||
|             OpcItem |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.#ctor(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             OpcItem |  | ||||||
|             </summary> |  | ||||||
|             <param name="itemId"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.AccessPath"> |  | ||||||
|             <summary> |  | ||||||
|             AccessPath |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.Blob"> |  | ||||||
|             <summary> |  | ||||||
|             Blob |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.BlobSize"> |  | ||||||
|             <summary> |  | ||||||
|             BlobSize |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.ClientHandle"> |  | ||||||
|             <summary> |  | ||||||
|             ClientHandle |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.IsActive"> |  | ||||||
|             <summary> |  | ||||||
|             active(1) or not(0) |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.ItemID"> |  | ||||||
|             <summary> |  | ||||||
|             数据项在opc server的完全名称 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.Quality"> |  | ||||||
|             <summary> |  | ||||||
|             Quality |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.RunTimeDataType"> |  | ||||||
|             <summary> |  | ||||||
|             RunTimeDataType |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.ServerHandle"> |  | ||||||
|             <summary> |  | ||||||
|             ServerHandle |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.TimeStamp"> |  | ||||||
|             <summary> |  | ||||||
|             TimeStamp |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem.Value"> |  | ||||||
|             <summary> |  | ||||||
|             Value |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcServer.AddGroup(System.String,System.Boolean,System.Int32,System.Single)"> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcServer.Browse(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             获取节点 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcServer.GetServerStatus"> |  | ||||||
|             <summary> |  | ||||||
|             服务器状态 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus"> |  | ||||||
|             <summary> |  | ||||||
|             ServerStatus |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.CurrentTime"> |  | ||||||
|             <summary> |  | ||||||
|             CurrentTime |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.LastUpdateTime"> |  | ||||||
|             <summary> |  | ||||||
|             LastUpdateTime |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.ServerState"> |  | ||||||
|             <summary> |  | ||||||
|             ServerState |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.StartTime"> |  | ||||||
|             <summary> |  | ||||||
|             StartTime |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.VendorInfo"> |  | ||||||
|             <summary> |  | ||||||
|             VendorInfo |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.Da.ServerStatus.Version"> |  | ||||||
|             <summary> |  | ||||||
|             Version |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Discovery.OpcDiscovery"> |  | ||||||
|             <summary> |  | ||||||
|             OpcDiscovery |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.Discovery.OpcDiscovery.GetOpcServer(System.String,System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             GetOpcServer |  | ||||||
|             </summary> |  | ||||||
|             <param name="serverName"></param> |  | ||||||
|             <param name="host"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IConnectionPoint"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IConnectionPointContainer"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumConnectionPoints"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumConnections"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumGUID"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumString"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumUnknown"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCCommon"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCEnumGUID"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServerList"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServerList2"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCShutdown"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CONNECTDATA"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSEDIRECTION"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSEFILTER"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSETYPE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCDATASOURCE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCENUMSCOPE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCEUTYPE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCNAMESPACETYPE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCSERVERSTATE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_OPCDAServer10"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_OPCDAServer20"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_OPCDAServer30"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.CATID_XMLDAServer10"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IEnumOPCItemAttributes"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCAsyncIO"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCAsyncIO2"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCAsyncIO3"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCBrowse"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCBrowseServerAddressSpace"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCDataCallback"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCGroupStateMgt"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCGroupStateMgt2"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemDeadbandMgt"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemIO"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemMgt"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemProperties"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCItemSamplingMgt"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCPublicGroupStateMgt"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServer"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCServerPublicGroups"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCSyncIO"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.IOPCSyncIO2"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCBROWSEELEMENT"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCGROUPHEADER"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCGROUPHEADERWRITE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMATTRIBUTES"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMDEF"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMHEADER1"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMHEADER2"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMHEADERWRITE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMPROPERTIES"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMPROPERTY"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMRESULT"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMSTATE"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCITEMVQT"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.OPCSERVERSTATUS"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.Constants"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.Qualities"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.Rcw.Properties"> |  | ||||||
|             <exclude /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.DataChangedEventHandler"> |  | ||||||
|             <summary> |  | ||||||
|             订阅变化项 |  | ||||||
|             </summary> |  | ||||||
|             <param name="values"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient"> |  | ||||||
|             <summary> |  | ||||||
|             OPCDAClient |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ItemDicts"> |  | ||||||
|             <summary> |  | ||||||
|             当前保存的需订阅列表 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.#ctor(ThingsGateway.Foundation.ILog)"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|             <param name="logger"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="E:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.DataChangedHandler"> |  | ||||||
|             <summary> |  | ||||||
|             数据变化事件 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.IsConnected"> |  | ||||||
|             <summary> |  | ||||||
|             是否连接成功 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.OPCNode"> |  | ||||||
|             <summary> |  | ||||||
|             当前配置 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.AddItems(System.Collections.Generic.Dictionary{System.String,System.Collections.Generic.List{ThingsGateway.Foundation.Adapter.OPCDA.Da.OpcItem}})"> |  | ||||||
|             <summary> |  | ||||||
|             添加节点,需要在连接成功后执行 |  | ||||||
|             </summary> |  | ||||||
|             <param name="items">组名称/变量节点,注意每次添加的组名称不能相同</param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.AddItemsWithSave(System.Collections.Generic.List{System.String})"> |  | ||||||
|             <summary> |  | ||||||
|             设置节点并保存,每次重连会自动添加节点 |  | ||||||
|             </summary> |  | ||||||
|             <param name="items"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Connect"> |  | ||||||
|             <summary> |  | ||||||
|             连接服务器 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Disconnect"> |  | ||||||
|             <summary> |  | ||||||
|             断开连接 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.GetBrowseElements(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             浏览节点 |  | ||||||
|             </summary> |  | ||||||
|             <param name="itemId"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.GetServerStatus"> |  | ||||||
|             <summary> |  | ||||||
|             获取服务状态 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Init(ThingsGateway.Foundation.Adapter.OPCDA.OPCNode)"> |  | ||||||
|             <summary> |  | ||||||
|             初始化设置 |  | ||||||
|             </summary> |  | ||||||
|             <param name="node"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ReadItemsWithGroup(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             按OPC组读取组内变量,结果会在订阅事件中返回 |  | ||||||
|             </summary> |  | ||||||
|             <param name="groupName">组名称,值为null时读取全部组</param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.RemoveItems(System.Collections.Generic.List{System.String})"> |  | ||||||
|             <summary> |  | ||||||
|             移除节点 |  | ||||||
|             </summary> |  | ||||||
|             <param name="items"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.ToString"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.WriteItem(System.Collections.Generic.Dictionary{System.String,Newtonsoft.Json.Linq.JToken})"> |  | ||||||
|             <summary> |  | ||||||
|             批量写入值 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient.Dispose(System.Boolean)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode"> |  | ||||||
|             <summary> |  | ||||||
|             OPCDA连接配置项 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.ActiveSubscribe"> |  | ||||||
|             <summary> |  | ||||||
|             是否订阅 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.CheckRate"> |  | ||||||
|             <summary> |  | ||||||
|             内部检测重连间隔/min |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.DeadBand"> |  | ||||||
|             <summary> |  | ||||||
|             死区 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.GroupSize"> |  | ||||||
|             <summary> |  | ||||||
|             分组大小 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.OPCIP"> |  | ||||||
|             <summary> |  | ||||||
|             OPCIP |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.OPCName"> |  | ||||||
|             <summary> |  | ||||||
|             OPCNAME |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.UpdateRate"> |  | ||||||
|             <summary> |  | ||||||
|             订阅间隔 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCDA.OPCNode.ToString"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|     </members> |  | ||||||
| </doc> |  | ||||||
| @@ -1,468 +0,0 @@ | |||||||
| <?xml version="1.0"?> |  | ||||||
| <doc> |  | ||||||
|     <assembly> |  | ||||||
|         <name>ThingsGateway.Foundation.Adapter.OPCUA</name> |  | ||||||
|     </assembly> |  | ||||||
|     <members> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.CollectionExtensions.RemoveWhere``1(System.Collections.Generic.ICollection{``0},System.Func{``0,System.Boolean})"> |  | ||||||
|             <summary> |  | ||||||
|             移除符合条件的元素 |  | ||||||
|             </summary> |  | ||||||
|             <typeparam name="T"></typeparam> |  | ||||||
|             <param name="this"></param> |  | ||||||
|             <param name="where"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.CollectionExtensions.SelectAsync``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,System.Threading.Tasks.Task{``1}})"> |  | ||||||
|             <summary> |  | ||||||
|             异步Select |  | ||||||
|             </summary> |  | ||||||
|             <typeparam name="T"></typeparam> |  | ||||||
|             <typeparam name="TResult"></typeparam> |  | ||||||
|             <param name="source"></param> |  | ||||||
|             <param name="selector"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils"> |  | ||||||
|             <summary> |  | ||||||
|             辅助类 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.Browse(Opc.Ua.Client.ISession,Opc.Ua.BrowseDescriptionCollection,System.Boolean)"> |  | ||||||
|             <summary> |  | ||||||
|             Browses the address space and returns the references found. |  | ||||||
|             </summary> |  | ||||||
|             <param name="session">The session.</param> |  | ||||||
|             <param name="nodesToBrowse">The set of browse operations to perform.</param> |  | ||||||
|             <param name="throwOnError">if set to <c>true</c> a exception will be thrown on an error.</param> |  | ||||||
|             <returns> |  | ||||||
|             The references found. Null if an error occurred. |  | ||||||
|             </returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.PrepareBrowseNext(Opc.Ua.BrowseResultCollection)"> |  | ||||||
|             <summary> |  | ||||||
|             Create the continuation point collection from the browse result |  | ||||||
|             collection for the BrowseNext service. |  | ||||||
|             </summary> |  | ||||||
|             <param name="browseResultCollection">The browse result collection to use.</param> |  | ||||||
|             <returns>The collection of continuation points for the BrowseNext service.</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.BrowseAsync(Opc.Ua.Client.ISession,Opc.Ua.BrowseDescriptionCollection,System.Boolean,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             浏览地址空间 |  | ||||||
|             </summary> |  | ||||||
|             <param name="session"></param> |  | ||||||
|             <param name="nodesToBrowse"></param> |  | ||||||
|             <param name="throwOnError"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|             <exception cref="T:Opc.Ua.ServiceResultException"></exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.BrowseAsync(Opc.Ua.Client.ISession,Opc.Ua.BrowseDescription,System.Boolean,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             浏览地址空间 |  | ||||||
|             </summary> |  | ||||||
|             <param name="session"></param> |  | ||||||
|             <param name="nodeToBrowse"></param> |  | ||||||
|             <param name="throwOnError"></param> |  | ||||||
|             <param name="cancellationToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|             <exception cref="T:Opc.Ua.ServiceResultException"></exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.BrowseSuperTypesAsync(Opc.Ua.Client.ISession,Opc.Ua.NodeId,System.Boolean)"> |  | ||||||
|             <summary> |  | ||||||
|             浏览地址空间并返回指定类型的所有节点 |  | ||||||
|             </summary> |  | ||||||
|             <param name="session"></param> |  | ||||||
|             <param name="typeId"></param> |  | ||||||
|             <param name="throwOnError"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|             <exception cref="T:Opc.Ua.ServiceResultException"></exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.CollectFieldsForInstanceAsync(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.SimpleAttributeOperandCollection,System.Collections.Generic.List{Opc.Ua.NodeId})"> |  | ||||||
|             <summary> |  | ||||||
|             Collects the fields for the instance. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.CollectFieldsForType(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.SimpleAttributeOperandCollection,System.Collections.Generic.List{Opc.Ua.NodeId})"> |  | ||||||
|             <summary> |  | ||||||
|             Collects the fields for the type. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.ConstructEventAsync(Opc.Ua.Client.ISession,Opc.Ua.Client.MonitoredItem,Opc.Ua.EventFieldList,System.Collections.Generic.Dictionary{Opc.Ua.NodeId,System.Type},System.Collections.Generic.Dictionary{Opc.Ua.NodeId,Opc.Ua.NodeId})"> |  | ||||||
|             <summary> |  | ||||||
|             Constructs an event object from a notification. |  | ||||||
|             </summary> |  | ||||||
|             <param name="session">The session.</param> |  | ||||||
|             <param name="monitoredItem">The monitored item that produced the notification.</param> |  | ||||||
|             <param name="notification">The notification.</param> |  | ||||||
|             <param name="knownEventTypes">The known event types.</param> |  | ||||||
|             <param name="eventTypeMappings">Mapping between event types and known event types.</param> |  | ||||||
|             <returns> |  | ||||||
|             The event object. Null if the notification is not a valid event type. |  | ||||||
|             </returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.DiscoverServers(Opc.Ua.ApplicationConfiguration)"> |  | ||||||
|             <summary> |  | ||||||
|             Discovers the servers on the local machine. |  | ||||||
|             </summary> |  | ||||||
|             <param name="configuration">The configuration.</param> |  | ||||||
|             <returns>A list of server urls.</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.FindEventType(Opc.Ua.Client.MonitoredItem,Opc.Ua.EventFieldList)"> |  | ||||||
|             <summary> |  | ||||||
|             Finds the type of the event for the notification. |  | ||||||
|             </summary> |  | ||||||
|             <param name="monitoredItem">The monitored item.</param> |  | ||||||
|             <param name="notification">The notification.</param> |  | ||||||
|             <returns>The NodeId of the EventType.</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.GetAttributeDisplayText(Opc.Ua.Client.ISession,System.UInt32,Opc.Ua.Variant)"> |  | ||||||
|             <summary> |  | ||||||
|             指定的属性的显示文本。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.SelectEndpoint(System.String,System.Boolean)"> |  | ||||||
|             <summary> |  | ||||||
|             Finds the endpoint that best matches the current settings. |  | ||||||
|             </summary> |  | ||||||
|             <param name="discoveryUrl">The discovery URL.</param> |  | ||||||
|             <param name="useSecurity">if set to <c>true</c> select an endpoint that uses security.</param> |  | ||||||
|             <returns>The best available endpoint.</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.TranslateBrowsePaths(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.NamespaceTable,System.Threading.CancellationToken,System.String[])"> |  | ||||||
|             <summary> |  | ||||||
|             返回一组相对路径的节点id |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.CollectFieldsAsync(Opc.Ua.Client.ISession,Opc.Ua.NodeId,Opc.Ua.QualifiedNameCollection,Opc.Ua.SimpleAttributeOperandCollection,System.Collections.Generic.List{Opc.Ua.NodeId},System.Collections.Generic.Dictionary{Opc.Ua.NodeId,Opc.Ua.QualifiedNameCollection})"> |  | ||||||
|             <summary> |  | ||||||
|             Collects the fields for the instance node. |  | ||||||
|             </summary> |  | ||||||
|             <param name="session">The session.</param> |  | ||||||
|             <param name="nodeId">The node id.</param> |  | ||||||
|             <param name="parentPath">The parent path.</param> |  | ||||||
|             <param name="fields">The event fields.</param> |  | ||||||
|             <param name="fieldNodeIds">The node id for the declaration of the field.</param> |  | ||||||
|             <param name="foundNodes">The table of found nodes.</param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.ContainsPath(Opc.Ua.SimpleAttributeOperandCollection,Opc.Ua.QualifiedNameCollection)"> |  | ||||||
|             <summary> |  | ||||||
|             判断指定的select子句包含的浏览路径。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.GetAccessLevelDisplayText(System.Byte)"> |  | ||||||
|              <summary> |  | ||||||
|             访问级别属性的显示文本。 |  | ||||||
|              </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.FormUtils.GetEventNotifierDisplayText(System.Byte)"> |  | ||||||
|             <summary> |  | ||||||
|             事件通知属性的显示文本 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils"> |  | ||||||
|             <summary> |  | ||||||
|             扩展方法 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.Decode(Opc.Ua.IServiceMessageContext,Opc.Ua.NodeId,Opc.Ua.BuiltInType,System.Int32,Newtonsoft.Json.Linq.JToken)"> |  | ||||||
|             <summary> |  | ||||||
|             解析获取DataValue |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecoderObject(Opc.Ua.IServiceMessageContext,Opc.Ua.NodeId,Opc.Ua.BuiltInType,System.Int32,Newtonsoft.Json.Linq.JToken)"> |  | ||||||
|             <summary> |  | ||||||
|             解析获取object |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.DecodeRawData(Opc.Ua.JsonDecoder,Opc.Ua.BuiltInType,System.Int32,System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             DecodeRawData |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.Encode(Opc.Ua.IServiceMessageContext,Opc.Ua.BuiltInType,System.Object)"> |  | ||||||
|             <summary> |  | ||||||
|             OPCUAValue解析为Jtoken |  | ||||||
|             </summary> |  | ||||||
|             <param name="Context"></param> |  | ||||||
|             <param name="type"></param> |  | ||||||
|             <param name="value"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.CreateEncoder(Opc.Ua.IServiceMessageContext,System.IO.Stream,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"> |  | ||||||
|             <summary> |  | ||||||
|             CreateEncoder |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.JsonUtils.CalculateActualValueRank(Newtonsoft.Json.Linq.JToken)"> |  | ||||||
|             <summary> |  | ||||||
|             维度 |  | ||||||
|             </summary> |  | ||||||
|             <param name="jToken"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode"> |  | ||||||
|             <summary> |  | ||||||
|             OPCUAClient配置项 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.OPCUrl"> |  | ||||||
|             <summary> |  | ||||||
|             OPCUrl |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.UserName"> |  | ||||||
|             <summary> |  | ||||||
|             登录账号 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.Password"> |  | ||||||
|             <summary> |  | ||||||
|             登录密码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.CheckDomain"> |  | ||||||
|             <summary> |  | ||||||
|             检查域 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.UpdateRate"> |  | ||||||
|             <summary> |  | ||||||
|             更新间隔 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.ActiveSubscribe"> |  | ||||||
|             <summary> |  | ||||||
|             是否订阅 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.GroupSize"> |  | ||||||
|             <summary> |  | ||||||
|             分组大小 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.DeadBand"> |  | ||||||
|             <summary> |  | ||||||
|             死区 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.KeepAliveInterval"> |  | ||||||
|             <summary> |  | ||||||
|             KeepAliveInterval/ms |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.IsUseSecurity"> |  | ||||||
|             <summary> |  | ||||||
|             安全策略 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCNode.ToString"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCUA.DataChangedEventHandler"> |  | ||||||
|             <summary> |  | ||||||
|             订阅委托 |  | ||||||
|             </summary> |  | ||||||
|             <param name="value"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient"> |  | ||||||
|             <summary> |  | ||||||
|             OPCUAClient |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.OPCNode"> |  | ||||||
|             <summary> |  | ||||||
|             当前配置 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ProductUri"> |  | ||||||
|             <summary> |  | ||||||
|             ProductUri |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Variables"> |  | ||||||
|             <summary> |  | ||||||
|             当前保存的变量名称列表 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient._variableDicts"> |  | ||||||
|             <summary> |  | ||||||
|             当前的变量名称/OPC变量节点 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.dic_subscriptions"> |  | ||||||
|             <summary> |  | ||||||
|             当前的订阅组,组名称/组 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReConnectHandler"> |  | ||||||
|             <summary> |  | ||||||
|             SessionReconnectHandler |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.#ctor(ThingsGateway.Foundation.ILog)"> |  | ||||||
|             <summary> |  | ||||||
|             默认的构造函数,实例化一个新的OPC UA类 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="E:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.DataChangedHandler"> |  | ||||||
|             <summary> |  | ||||||
|             订阅 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.AppConfig"> |  | ||||||
|             <summary> |  | ||||||
|             配置信息 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Connected"> |  | ||||||
|             <summary> |  | ||||||
|             连接状态 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.OPCUAName"> |  | ||||||
|             <summary> |  | ||||||
|             OPCUAClient |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Session"> |  | ||||||
|             <summary> |  | ||||||
|             当前活动会话。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.AddSubscriptionAsync(System.String,System.String[])"> |  | ||||||
|             <summary> |  | ||||||
|             新增订阅,需要指定订阅组名称,订阅的tag名数组 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.RemoveAllSubscription"> |  | ||||||
|             <summary> |  | ||||||
|             移除所有的订阅消息 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.RemoveSubscription(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             移除订阅消息 |  | ||||||
|             </summary> |  | ||||||
|             <param name="subscriptionName">组名称</param> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.BrowseNodeReferenceAsync(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             浏览一个节点的引用 |  | ||||||
|             </summary> |  | ||||||
|             <param name="tag">节点值</param> |  | ||||||
|             <returns>引用节点描述</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.CallMethodByNodeId(System.String,System.String,System.Object[])"> |  | ||||||
|             <summary> |  | ||||||
|             调用服务器的方法 |  | ||||||
|             </summary> |  | ||||||
|             <param name="tagParent">方法的父节点tag</param> |  | ||||||
|             <param name="tag">方法的节点tag</param> |  | ||||||
|             <param name="args">传递的参数</param> |  | ||||||
|             <returns>输出的结果值</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadHistoryRawDataValues(System.String,System.DateTime,System.DateTime,System.UInt32,System.Boolean,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取历史数据 |  | ||||||
|             </summary> |  | ||||||
|             <param name="tag">节点的索引</param> |  | ||||||
|             <param name="start">开始时间</param> |  | ||||||
|             <param name="end">结束时间</param> |  | ||||||
|             <param name="count">读取的个数</param> |  | ||||||
|             <param name="containBound">是否包含边界</param> |  | ||||||
|             <param name="cancellationToken">cancellationToken</param> |  | ||||||
|             <returns>读取的数据列表</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ConnectAsync"> |  | ||||||
|             <summary> |  | ||||||
|             连接到服务器 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Disconnect"> |  | ||||||
|             <summary> |  | ||||||
|             断开连接。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ConnectAsync(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             Creates a new session. |  | ||||||
|             </summary> |  | ||||||
|             <returns>The new session object.</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadJTokenValueAsync(System.String[],System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             从服务器读取值 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.WriteNodeAsync(System.Collections.Generic.Dictionary{System.String,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             异步写opc标签 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadJTokenValueAsync(Opc.Ua.NodeId[],System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             从服务器读取值 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNodeAsync(System.String,System.Boolean,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             从服务器或缓存读取节点 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNoteAttributeAsync(System.String,System.UInt32,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取一个节点的所有属性 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNoteAttributeAsync(System.Collections.Generic.List{System.String},System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取节点的所有属性 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.ReadNoteAttributes(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             读取一个节点的所有属性 |  | ||||||
|             </summary> |  | ||||||
|             <param name="tag">节点信息</param> |  | ||||||
|             <returns>节点的特性值</returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Dispose(System.Boolean)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient.Server_ReconnectComplete(System.Object,System.EventArgs)"> |  | ||||||
|             <summary> |  | ||||||
|             连接处理器连接事件处理完成。 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute"> |  | ||||||
|             <summary> |  | ||||||
|             读取属性过程中用于描述的 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.Name"> |  | ||||||
|             <summary> |  | ||||||
|             属性的名称 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.StatusCode"> |  | ||||||
|             <summary> |  | ||||||
|             操作结果状态描述 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.Type"> |  | ||||||
|             <summary> |  | ||||||
|             属性的类型描述 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.OPCUA.OPCNodeAttribute.Value"> |  | ||||||
|             <summary> |  | ||||||
|             属性的值,如果读取错误,返回文本描述 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|     </members> |  | ||||||
| </doc> |  | ||||||
| @@ -1,131 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using System.Collections.Generic; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
|  |  | ||||||
| public partial class SiemensS7PLC : ReadWriteDevicesTcpClientBase |  | ||||||
| { |  | ||||||
|     private static OperResult<byte[]> GetWriteBitCommand(string address, bool data) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var result = SiemensAddress.ParseFrom(address); |  | ||||||
|             return SiemensHelper.GetWriteBitCommand(result, data); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     private OperResult<List<byte[]>> GetReadByteCommand(string address, int length) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var from = SiemensAddress.ParseFrom(address, length); |  | ||||||
|             ushort num1 = 0; |  | ||||||
|             var listBytes = new List<byte[]>(); |  | ||||||
|             while (num1 < length) |  | ||||||
|             { |  | ||||||
|                 //pdu长度,重复生成报文,直至全部生成 |  | ||||||
|                 ushort num2 = (ushort)Math.Min(length - num1, pdu_length); |  | ||||||
|                 from.Length = num2; |  | ||||||
|                 var result = GetReadByteCommand(new SiemensAddress[1] { from }); |  | ||||||
|                 if (!result.IsSuccess) return new(result); |  | ||||||
|                 listBytes.AddRange(result.Content); |  | ||||||
|                 num1 += num2; |  | ||||||
|                 if (from.DataCode == (byte)S7WordLength.Timer || from.DataCode == (byte)S7WordLength.Counter) |  | ||||||
|                 { |  | ||||||
|                     from.Address += num2 / 2; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     from.Address += num2 * 8; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             return OperResult.CreateSuccessResult(listBytes); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult<List<byte[]>>(ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private OperResult<List<byte[]>> GetReadByteCommand(SiemensAddress[] siemensAddress) |  | ||||||
|     { |  | ||||||
|         if (siemensAddress.Length <= 19) |  | ||||||
|         { |  | ||||||
|             return ByteTransformUtil.GetResultFromBytes(SiemensHelper.GetReadCommand(siemensAddress), m => new List<byte[]>() { m }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         List<byte[]> byteList = new(); |  | ||||||
|         List<SiemensAddress[]> s7AddressDataArrayList = siemensAddress.ArraySplitByLength(19); |  | ||||||
|         for (int index = 0; index < s7AddressDataArrayList.Count; ++index) |  | ||||||
|         { |  | ||||||
|             var result = GetReadByteCommand(s7AddressDataArrayList[index]); |  | ||||||
|             if (!result.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 return result; |  | ||||||
|             } |  | ||||||
|             byteList.AddRange(result.Content); |  | ||||||
|         } |  | ||||||
|         return OperResult.CreateSuccessResult(byteList); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private OperResult<List<byte[]>> GetWriteByteCommand(string address, byte[] value) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var s_Address = SiemensAddress.ParseFrom(address); |  | ||||||
|  |  | ||||||
|             return GetWriteByteCommand(s_Address, value); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new(ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// DefalutConverter |  | ||||||
|     /// </summary> |  | ||||||
|     public static ThingsGatewayBitConverter DefalutConverter = new(BitConverter.IsLittleEndian ? EndianType.Little : EndianType.Big); |  | ||||||
|     private OperResult<List<byte[]>> GetWriteByteCommand(SiemensAddress address, byte[] value) |  | ||||||
|     { |  | ||||||
|         int length1 = value.Length; |  | ||||||
|         ushort index = 0; |  | ||||||
|         List<byte[]> bytes = new(); |  | ||||||
|         while (index < length1) |  | ||||||
|         { |  | ||||||
|             //pdu长度,重复生成报文,直至全部生成 |  | ||||||
|             ushort length2 = (ushort)Math.Min(length1 - index, pdu_length); |  | ||||||
|             byte[] data = DefalutConverter.ToByte(value, index, length2); |  | ||||||
|             OperResult<byte[]> result1 = SiemensHelper.GetWriteByteCommand(address, data); |  | ||||||
|             if (!result1.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 return new(result1); |  | ||||||
|             } |  | ||||||
|             bytes.Add(result1.Content); |  | ||||||
|             index += length2; |  | ||||||
|             address.Address += length2 * 8; |  | ||||||
|         } |  | ||||||
|         return OperResult.CreateSuccessResult(bytes); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,336 +0,0 @@ | |||||||
| <?xml version="1.0"?> |  | ||||||
| <doc> |  | ||||||
|     <assembly> |  | ||||||
|         <name>ThingsGateway.Foundation.Adapter.Siemens</name> |  | ||||||
|     </assembly> |  | ||||||
|     <members> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.S7Area"> |  | ||||||
|             <summary> |  | ||||||
|             区域 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.PE"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.PA"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.MK"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.DB"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.CT"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.TM"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.AI"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7Area.AQ"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress"> |  | ||||||
|             <summary> |  | ||||||
|             西门子PLC地址数据信息 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.BitCode"> |  | ||||||
|             <summary> |  | ||||||
|             bit位偏移 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.DataCode"> |  | ||||||
|             <summary> |  | ||||||
|             数据块代码 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.DbBlock"> |  | ||||||
|             <summary> |  | ||||||
|             DB块数据信息 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.GetAddressStart(System.String,System.Boolean)"> |  | ||||||
|             <summary> |  | ||||||
|             获取起始地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="address"></param> |  | ||||||
|             <param name="isCounterOrTimer"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.GetBitCode(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             获取bit |  | ||||||
|             </summary> |  | ||||||
|             <param name="address"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.ParseFrom(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             解析地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="address"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.ParseFrom(System.String,System.Int32)"> |  | ||||||
|             <summary> |  | ||||||
|             解析地址 |  | ||||||
|             </summary> |  | ||||||
|             <param name="address"></param> |  | ||||||
|             <param name="length"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.Parse(System.String,System.Int32)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensAddress.ToString"> |  | ||||||
|             <inheritdoc /> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.DateTime"> |  | ||||||
|             <summary> |  | ||||||
|             https://github.com/S7NetPlus/s7netplus/blob/develop/S7.Net/Types/DateTime.cs |  | ||||||
|             Contains the methods to convert between <see cref="T:System.DateTime"/> and S7 representation of datetime values. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMaximumDateTime"> |  | ||||||
|             <summary> |  | ||||||
|             The maximum <see cref="T:System.DateTime"/> value supported by the specification. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMinimumDateTime"> |  | ||||||
|             <summary> |  | ||||||
|             The minimum <see cref="T:System.DateTime"/> value supported by the specification. |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.FromByteArray(System.Byte[])"> |  | ||||||
|             <summary> |  | ||||||
|             Parses a <see cref="T:System.DateTime"/> value from bytes. |  | ||||||
|             </summary> |  | ||||||
|             <param name="bytes">Input bytes read from PLC.</param> |  | ||||||
|             <returns>A <see cref="T:System.DateTime"/> object representing the value read from PLC.</returns> |  | ||||||
|             <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the length of |  | ||||||
|               <paramref name="bytes"/> is not 8 or any value in <paramref name="bytes"/> |  | ||||||
|               is outside the valid range of values.</exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToArray(System.Byte[])"> |  | ||||||
|             <summary> |  | ||||||
|             Parses an array of <see cref="T:System.DateTime"/> values from bytes. |  | ||||||
|             </summary> |  | ||||||
|             <param name="bytes">Input bytes read from PLC.</param> |  | ||||||
|             <returns>An array of <see cref="T:System.DateTime"/> objects representing the values read from PLC.</returns> |  | ||||||
|             <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the length of |  | ||||||
|               <paramref name="bytes"/> is not a multiple of 8 or any value in |  | ||||||
|               <paramref name="bytes"/> is outside the valid range of values.</exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToByteArray(System.DateTime)"> |  | ||||||
|             <summary> |  | ||||||
|             Converts a <see cref="T:System.DateTime"/> value to a byte array. |  | ||||||
|             </summary> |  | ||||||
|             <param name="dateTime">The DateTime value to convert.</param> |  | ||||||
|             <returns>A byte array containing the S7 date time representation of <paramref name="dateTime"/>.</returns> |  | ||||||
|             <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the value of |  | ||||||
|               <paramref name="dateTime"/> is before <see cref="P:SpecMinimumDateTime"/> |  | ||||||
|               or after <see cref="P:SpecMaximumDateTime"/>.</exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToByteArray(System.DateTime[])"> |  | ||||||
|             <summary> |  | ||||||
|             Converts an array of <see cref="T:System.DateTime"/> values to a byte array. |  | ||||||
|             </summary> |  | ||||||
|             <param name="dateTimes">The DateTime values to convert.</param> |  | ||||||
|             <returns>A byte array containing the S7 date time representations of <paramref name="dateTimes"/>.</returns> |  | ||||||
|             <exception cref="T:System.ArgumentOutOfRangeException">Thrown when any value of |  | ||||||
|               <paramref name="dateTimes"/> is before <see cref="P:SpecMinimumDateTime"/> |  | ||||||
|               or after <see cref="P:SpecMaximumDateTime"/>.</exception> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensHelper.S7_MULRW_HEADER"> |  | ||||||
|             <summary> |  | ||||||
|             S7连读写请求头(包含ISO头和COTP头)  |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Bit"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Byte"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Char"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Word"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Int"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.DWord"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.DInt"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Real"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Counter"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.S7WordLength.Timer"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage.HeadBytesLength"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage.CheckHeadBytes(System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S200"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S200Smart"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S300"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S400"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S1200"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum.S1500"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC"> |  | ||||||
|             <summary> |  | ||||||
|             相关命令含义源自网络资料/Shrap7/s7netplus |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.#ctor(ThingsGateway.Foundation.TcpClient,ThingsGateway.Foundation.Adapter.Siemens.SiemensEnum)"> |  | ||||||
|             <summary> |  | ||||||
|             传入PLC类型,程序内会改变相应PLC类型的S7协议LocalTSAP, RemoteTSAP等 |  | ||||||
|             </summary> |  | ||||||
|             <param name="tcpClient"></param> |  | ||||||
|             <param name="siemensPLCEnum"></param> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.CurrentPlc"> |  | ||||||
|             <summary> |  | ||||||
|             当前PLC类型 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.GetAddressDescription"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.GetBitOffset(System.String)"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|             <param name="address"></param> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.DestTSAP"> |  | ||||||
|             <summary> |  | ||||||
|             远程TSAP,需重新连接 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.LocalTSAP"> |  | ||||||
|             <summary> |  | ||||||
|             本地TSAP,需重新连接 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.PDULength"> |  | ||||||
|             <summary> |  | ||||||
|             PDULength |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.Rack"> |  | ||||||
|             <summary> |  | ||||||
|             机架号,需重新连接 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.Slot"> |  | ||||||
|             <summary> |  | ||||||
|             槽号,需重新连接 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadDateAsync(System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取日期 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadDateTimeAsync(System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取时间 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.ReadStringAsync(System.String,System.Text.Encoding,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             读取变长字符串 |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.SetDataAdapter"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteAsync(System.String,System.String,System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteDateAsync(System.String,System.DateTime,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             写入日期 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC.WriteDateTimeAsync(System.String,System.DateTime,System.Threading.CancellationToken)"> |  | ||||||
|             <summary> |  | ||||||
|             写入时间 |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter"> |  | ||||||
|             <summary> |  | ||||||
|             SiemensS7PLCDataHandleAdapter |  | ||||||
|             </summary> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter.PackCommand(System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter.GetInstance"> |  | ||||||
|             <summary> |  | ||||||
|             <inheritdoc/> |  | ||||||
|             </summary> |  | ||||||
|             <returns></returns> |  | ||||||
|         </member> |  | ||||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLCDataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Siemens.SiemensMessage,System.Byte[],System.Byte[],System.Byte[])"> |  | ||||||
|             <inheritdoc/> |  | ||||||
|         </member> |  | ||||||
|     </members> |  | ||||||
| </doc> |  | ||||||
| @@ -1,121 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 读写扩展方法 |  | ||||||
| /// </summary> |  | ||||||
| public static class ReadWriteDevicesExtensions |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 在返回的字节数组中解析每个变量的值 |  | ||||||
|     /// 根据每个变量的<see cref="IDeviceVariableRunTime.Index"/> |  | ||||||
|     /// 不支持变长字符串类型变量,一定不能存在于变量List中 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="values">设备变量List</param> |  | ||||||
|     /// <param name="plc">设备</param> |  | ||||||
|     /// <param name="buffer">返回的字节数组</param> |  | ||||||
|     /// <param name="startIndex">开始序号</param> |  | ||||||
|     public static void PraseStructContent<T>(this IList<T> values, IReadWrite plc, byte[] buffer, int startIndex = 0) where T : IDeviceVariableRunTime |  | ||||||
|     { |  | ||||||
|         foreach (IDeviceVariableRunTime organizedVariable in values) |  | ||||||
|         { |  | ||||||
|             var deviceValue = organizedVariable; |  | ||||||
|             IThingsGatewayBitConverter byteConverter = deviceValue.ThingsGatewayBitConverter; |  | ||||||
|             var dataType = organizedVariable.DataTypeEnum; |  | ||||||
|             int index = organizedVariable.Index; |  | ||||||
|             switch (dataType) |  | ||||||
|             { |  | ||||||
|                 case DataTypeEnum.String: |  | ||||||
|                     Set(organizedVariable, byteConverter.ToString(buffer, index + startIndex, byteConverter.Length ?? 1)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Boolean: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToBoolean(buffer, index + (startIndex * 8), byteConverter.Length.Value, plc.IsBitReverse(organizedVariable.VariableAddress)) : |  | ||||||
|                         byteConverter.ToBoolean(buffer, index + (startIndex * 8), plc.IsBitReverse(organizedVariable.VariableAddress)) |  | ||||||
|                         ); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Byte: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                         byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToByte(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToByte(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Int16: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToInt16(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToInt16(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.UInt16: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToUInt16(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToUInt16(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Int32: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToInt32(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToInt32(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.UInt32: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToUInt32(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToUInt32(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Int64: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToInt64(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToInt64(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.UInt64: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToUInt64(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToUInt64(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Single: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToSingle(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToSingle(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 case DataTypeEnum.Double: |  | ||||||
|                     Set(organizedVariable, |  | ||||||
|                          byteConverter.Length > 1 ? |  | ||||||
|                         byteConverter.ToDouble(buffer, index + (startIndex), byteConverter.Length.Value) : |  | ||||||
|                         byteConverter.ToDouble(buffer, index + startIndex)); |  | ||||||
|                     break; |  | ||||||
|                 default: |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         static void Set(IDeviceVariableRunTime organizedVariable, object num) |  | ||||||
|         { |  | ||||||
|             var operResult = organizedVariable.SetValue(num); ; |  | ||||||
|             if (!operResult.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 throw new Exception(operResult.Message); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,127 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using System.ComponentModel; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 服务设备 |  | ||||||
| /// </summary> |  | ||||||
| public abstract class ReadWriteDevicesTcpServerBase : ReadWriteDevicesBase |  | ||||||
| { |  | ||||||
|     /// <inheritdoc cref="ReadWriteDevicesTcpServerBase"/> |  | ||||||
|     public ReadWriteDevicesTcpServerBase(TcpService tcpService) |  | ||||||
|     { |  | ||||||
|         TcpService = tcpService; |  | ||||||
|         TcpService.Connecting += Connecting; |  | ||||||
|         TcpService.Connected += Connected; |  | ||||||
|         TcpService.Received += Received; |  | ||||||
|         TcpService.Disconnecting += Disconnecting; |  | ||||||
|         TcpService.Disconnected += Disconnected; |  | ||||||
|         Logger = TcpService.Logger; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 连接超时时间 |  | ||||||
|     /// </summary> |  | ||||||
|     [Description("连接超时时间")] |  | ||||||
|     public ushort ConnectTimeOut { get; set; } = 3000; |  | ||||||
|     /// <summary> |  | ||||||
|     /// 服务管理对象 |  | ||||||
|     /// </summary> |  | ||||||
|     public TcpService TcpService { get; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void Connect(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         TcpService.Start(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task ConnectAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return Task.Run(() => TcpService.Start()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void Disconnect() |  | ||||||
|     { |  | ||||||
|         if (CascadeDisposal) |  | ||||||
|             TcpService.Stop(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void Dispose() |  | ||||||
|     { |  | ||||||
|         TcpService.Connecting -= Connecting; |  | ||||||
|         TcpService.Connected -= Connected; |  | ||||||
|         TcpService.Disconnecting -= Disconnecting; |  | ||||||
|         TcpService.Disconnected -= Disconnected; |  | ||||||
|         Disconnect(); |  | ||||||
|         if (CascadeDisposal) |  | ||||||
|             TcpService.SafeDispose(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string ToString() |  | ||||||
|     { |  | ||||||
|         return TcpService.ServerName; |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// 接收解析 |  | ||||||
|     /// </summary> |  | ||||||
|     protected virtual void Received(SocketClient client, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="client"></param> |  | ||||||
|     /// <param name="e"></param> |  | ||||||
|     protected virtual void Connected(SocketClient client, ConnectedEventArgs e) |  | ||||||
|     { |  | ||||||
|         Logger?.Debug(client.IP + ":" + client.Port + "连接成功"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected virtual void Connecting(SocketClient client, ConnectingEventArgs e) |  | ||||||
|     { |  | ||||||
|         Logger?.Debug(client.IP + ":" + client.Port + "正在连接"); |  | ||||||
|         SetDataAdapter(client); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected virtual void Disconnected(ITcpClientBase client, DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         Logger?.Debug(client.IP + ":" + client.Port + "断开连接-" + e.Message); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected virtual void Disconnecting(ITcpClientBase client, DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         Logger?.Debug(client.IP + ":" + client.Port + "正在主动断开连接-" + e.Message); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void Received(SocketClient client, ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             Received(client, requestInfo); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             Logger.Exception(this, ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,118 +0,0 @@ | |||||||
| #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.Extension; |  | ||||||
| /// <summary> |  | ||||||
| /// 对象拓展类 |  | ||||||
| /// </summary> |  | ||||||
| public static class ObjectExtensions |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 转换布尔值 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static bool ToBoolean(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch |  | ||||||
|     { |  | ||||||
|         "0" or "FALSE" => false, |  | ||||||
|         "1" or "TRUE" => true, |  | ||||||
|         _ => defaultValue, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// ToLong |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static long ToLong(this object value, long defaultValue = 0) |  | ||||||
|     { |  | ||||||
|         if (value == null || value.ToString().IsNullOrEmpty()) |  | ||||||
|         { |  | ||||||
|             return defaultValue; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (value is bool boolValue) |  | ||||||
|             { |  | ||||||
|                 return boolValue ? 1 : 0; |  | ||||||
|             } |  | ||||||
|             return Int64.TryParse(value.ToString(), out var n) ? n : defaultValue; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// ToInt |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static int ToInt(this object value, int defaultValue = 0) |  | ||||||
|     { |  | ||||||
|         if (value == null || value.ToString().IsNullOrEmpty()) |  | ||||||
|         { |  | ||||||
|             return defaultValue; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (value is bool boolValue) |  | ||||||
|             { |  | ||||||
|                 return boolValue ? 1 : 0; |  | ||||||
|             } |  | ||||||
|             return int.TryParse(value.ToString(), out int n) ? n : defaultValue; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// ToDecimal |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static decimal ToDecimal(this object value, int defaultValue = 0) |  | ||||||
|     { |  | ||||||
|         if (value is Double d) |  | ||||||
|         { |  | ||||||
|             return Double.IsNaN(d) ? defaultValue : (Decimal)d; |  | ||||||
|         } |  | ||||||
|         var str = value?.ToString(); |  | ||||||
|         if (str.IsNullOrEmpty()) |  | ||||||
|         { |  | ||||||
|             return defaultValue; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (value is bool boolValue) |  | ||||||
|             { |  | ||||||
|                 return boolValue ? 1 : 0; |  | ||||||
|             } |  | ||||||
|             return Decimal.TryParse(str, out var n) ? n : defaultValue; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// ToDecimal |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static double ToDouble(this object value, double defaultValue = 0) |  | ||||||
|     { |  | ||||||
|         if (value is Double d) |  | ||||||
|         { |  | ||||||
|             return Double.IsNaN(d) ? defaultValue : (Double)d; |  | ||||||
|         } |  | ||||||
|         var str = value?.ToString(); |  | ||||||
|         if (str.IsNullOrEmpty()) |  | ||||||
|         { |  | ||||||
|             return (double)defaultValue; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             if (value is bool boolValue) |  | ||||||
|             { |  | ||||||
|                 return boolValue ? 1 : 0; |  | ||||||
|             } |  | ||||||
|             return (double)(double.TryParse(str, out var n) ? n : defaultValue); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
| 	<ItemGroup Condition="'$(TargetFramework)'=='net45'"> |  | ||||||
| 		<Reference Include="Microsoft.CSharp" /> |  | ||||||
| 		<Reference Include="System.Web" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
| 	<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'"> |  | ||||||
| 		<PackageReference Include="Microsoft.CSharp" Version="4.7.0" PrivateAssets="All" /> |  | ||||||
| 		<PackageReference Include="System.Reflection.Emit.ILGeneration" Version="4.7.0" /> |  | ||||||
| 		<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
| 	 |  | ||||||
| 	<ItemGroup Condition="'$(TargetFramework)'!='net45'"> |  | ||||||
| 		<PackageReference Include="System.IO.Ports" Version="7.0.0" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
|  |  | ||||||
| @@ -1,275 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 消息通知类。内部全为弱引用。 |  | ||||||
|     /// </summary> |  | ||||||
|     public class AppMessenger |  | ||||||
|     { |  | ||||||
|         private static AppMessenger m_instance; |  | ||||||
|         private readonly ReaderWriterLockSlim m_lockSlim = new ReaderWriterLockSlim(); |  | ||||||
|         private readonly Dictionary<string, List<MessageInstance>> m_tokenAndInstance = new Dictionary<string, List<MessageInstance>>(); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 默认单例实例 |  | ||||||
|         /// </summary> |  | ||||||
|         public static AppMessenger Default |  | ||||||
|         { |  | ||||||
|             get |  | ||||||
|             { |  | ||||||
|                 if (m_instance != null) |  | ||||||
|                 { |  | ||||||
|                     return m_instance; |  | ||||||
|                 } |  | ||||||
|                 lock (typeof(AppMessenger)) |  | ||||||
|                 { |  | ||||||
|                     if (m_instance != null) |  | ||||||
|                     { |  | ||||||
|                         return m_instance; |  | ||||||
|                     } |  | ||||||
|                     m_instance = new AppMessenger(); |  | ||||||
|                     return m_instance; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 允许多广播注册 |  | ||||||
|         /// </summary> |  | ||||||
|         public bool AllowMultiple { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 添加 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="cancellationToken"></param> |  | ||||||
|         /// <param name="messageInstance"></param> |  | ||||||
|         /// <exception cref="MessageRegisteredException"></exception> |  | ||||||
|         public void Add(string cancellationToken, MessageInstance messageInstance) |  | ||||||
|         { |  | ||||||
|             using (var writeLock = new WriteLock(this.m_lockSlim)) |  | ||||||
|             { |  | ||||||
|                 if (this.m_tokenAndInstance.ContainsKey(cancellationToken)) |  | ||||||
|                 { |  | ||||||
|                     if (!this.AllowMultiple) |  | ||||||
|                     { |  | ||||||
|                         throw new MessageRegisteredException(TouchSocketCoreResource.TokenExisted.GetDescription(cancellationToken)); |  | ||||||
|                     } |  | ||||||
|                     this.m_tokenAndInstance[cancellationToken].Add(messageInstance); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     this.m_tokenAndInstance.Add(cancellationToken, new List<MessageInstance>() |  | ||||||
|                     { |  | ||||||
|                      messageInstance |  | ||||||
|                     }); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 判断能否触发该消息,意味着该消息是否已经注册。 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="cancellationToken"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public bool CanSendMessage(string cancellationToken) |  | ||||||
|         { |  | ||||||
|             using (var readLock = new ReadLock(this.m_lockSlim)) |  | ||||||
|             { |  | ||||||
|                 return this.m_tokenAndInstance.ContainsKey(cancellationToken); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 清除所有消息 |  | ||||||
|         /// </summary> |  | ||||||
|         public void Clear() |  | ||||||
|         { |  | ||||||
|             using (var writeLock = new WriteLock(this.m_lockSlim)) |  | ||||||
|             { |  | ||||||
|                 this.m_tokenAndInstance.Clear(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 获取所有消息 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public string[] GetAllMessage() |  | ||||||
|         { |  | ||||||
|             using (var readLock = new ReadLock(this.m_lockSlim)) |  | ||||||
|             { |  | ||||||
|                 return this.m_tokenAndInstance.Keys.ToArray(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 移除 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="cancellationToken"></param> |  | ||||||
|         public void Remove(string cancellationToken) |  | ||||||
|         { |  | ||||||
|             using (var writeLock = new WriteLock(this.m_lockSlim)) |  | ||||||
|             { |  | ||||||
|                 this.m_tokenAndInstance.Remove(cancellationToken); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 按对象移除 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="messageObject"></param> |  | ||||||
|         public void Remove(IMessageObject messageObject) |  | ||||||
|         { |  | ||||||
|             using (var writeLock = new WriteLock(this.m_lockSlim)) |  | ||||||
|             { |  | ||||||
|                 var key = new List<string>(); |  | ||||||
|  |  | ||||||
|                 foreach (var item in this.m_tokenAndInstance.Keys) |  | ||||||
|                 { |  | ||||||
|                     foreach (var item2 in this.m_tokenAndInstance[item].ToArray()) |  | ||||||
|                     { |  | ||||||
|                         if (messageObject == item2.MessageObject) |  | ||||||
|                         { |  | ||||||
|                             this.m_tokenAndInstance[item].Remove(item2); |  | ||||||
|                             if (this.m_tokenAndInstance[item].Count == 0) |  | ||||||
|                             { |  | ||||||
|                                 key.Add(item); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 foreach (var item in key) |  | ||||||
|                 { |  | ||||||
|                     this.m_tokenAndInstance.Remove(item); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送消息 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="cancellationToken"></param> |  | ||||||
|         /// <param name="parameters"></param> |  | ||||||
|         /// <exception cref="MessageNotFoundException"></exception> |  | ||||||
|         public Task SendAsync(string cancellationToken, params object[] parameters) |  | ||||||
|         { |  | ||||||
|             return Task.Run(() => |  | ||||||
|              { |  | ||||||
|                  using (var readLock = new ReadLock(this.m_lockSlim)) |  | ||||||
|                  { |  | ||||||
|                      if (this.m_tokenAndInstance.TryGetValue(cancellationToken, out var list)) |  | ||||||
|                      { |  | ||||||
|                          var clear = new List<MessageInstance>(); |  | ||||||
|  |  | ||||||
|                          foreach (var item in list) |  | ||||||
|                          { |  | ||||||
|                              if (!item.Info.IsStatic && !item.WeakReference.TryGetTarget(out _)) |  | ||||||
|                              { |  | ||||||
|                                  clear.Add(item); |  | ||||||
|                                  continue; |  | ||||||
|                              } |  | ||||||
|                              try |  | ||||||
|                              { |  | ||||||
|                                  item.Invoke(item.MessageObject, parameters); |  | ||||||
|                              } |  | ||||||
|                              catch |  | ||||||
|                              { |  | ||||||
|                              } |  | ||||||
|                          } |  | ||||||
|  |  | ||||||
|                          foreach (var item in clear) |  | ||||||
|                          { |  | ||||||
|                              list.Remove(item); |  | ||||||
|                          } |  | ||||||
|                      } |  | ||||||
|                      else |  | ||||||
|                      { |  | ||||||
|                          throw new MessageNotFoundException(TouchSocketCoreResource.MessageNotFound.GetDescription(cancellationToken)); |  | ||||||
|                      } |  | ||||||
|                  } |  | ||||||
|              }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送消息,当多播时,只返回最后一个返回值 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <typeparam name="T">返回值类型</typeparam> |  | ||||||
|         /// <param name="cancellationToken"></param> |  | ||||||
|         /// <param name="parameters"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         /// <exception cref="MessageNotFoundException"></exception> |  | ||||||
|         public Task<T> SendAsync<T>(string cancellationToken, params object[] parameters) |  | ||||||
|         { |  | ||||||
|             return Task.Run(() => |  | ||||||
|              { |  | ||||||
|                  using (var readLock = new ReadLock(this.m_lockSlim)) |  | ||||||
|                  { |  | ||||||
|                      if (this.m_tokenAndInstance.TryGetValue(cancellationToken, out var list)) |  | ||||||
|                      { |  | ||||||
|                          T result = default; |  | ||||||
|                          var clear = new List<MessageInstance>(); |  | ||||||
|                          for (var i = 0; i < list.Count; i++) |  | ||||||
|                          { |  | ||||||
|                              var item = list[i]; |  | ||||||
|                              if (!item.Info.IsStatic && !item.WeakReference.TryGetTarget(out _)) |  | ||||||
|                              { |  | ||||||
|                                  clear.Add(item); |  | ||||||
|                                  continue; |  | ||||||
|                              } |  | ||||||
|  |  | ||||||
|                              try |  | ||||||
|                              { |  | ||||||
|                                  if (i == list.Count - 1) |  | ||||||
|                                  { |  | ||||||
|                                      result = (T)item.Invoke(item.MessageObject, parameters); |  | ||||||
|                                  } |  | ||||||
|                                  else |  | ||||||
|                                  { |  | ||||||
|                                      item.Invoke(item.MessageObject, parameters); |  | ||||||
|                                  } |  | ||||||
|                              } |  | ||||||
|                              catch |  | ||||||
|                              { |  | ||||||
|                              } |  | ||||||
|                          } |  | ||||||
|  |  | ||||||
|                          foreach (var item in clear) |  | ||||||
|                          { |  | ||||||
|                              list.Remove(item); |  | ||||||
|                          } |  | ||||||
|                          return result; |  | ||||||
|                      } |  | ||||||
|                      else |  | ||||||
|                      { |  | ||||||
|                          throw new MessageNotFoundException(TouchSocketCoreResource.MessageNotFound.GetDescription(cancellationToken)); |  | ||||||
|                      } |  | ||||||
|                  } |  | ||||||
|              }); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,120 +0,0 @@ | |||||||
| #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 |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// DateHandleAdapterExtension |  | ||||||
|     /// </summary> |  | ||||||
|     public static class DataHandlingAdapterExtension |  | ||||||
|     { |  | ||||||
|         #region SingleStreamDataHandlingAdapter |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 将<see cref="TouchSocketConfig"/>中的配置,装载在<see cref="SingleStreamDataHandlingAdapter"/>上。 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="adapter"></param> |  | ||||||
|         /// <param name="config"></param> |  | ||||||
|         public static void Config(this SingleStreamDataHandlingAdapter adapter, TouchSocketConfig config) |  | ||||||
|         { |  | ||||||
|             if (config.GetValue(DataHandlingAdapterExtension.MaxPackageSizeProperty) is int v1) |  | ||||||
|             { |  | ||||||
|                 adapter.MaxPackageSize = v1; |  | ||||||
|             } |  | ||||||
|             if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty) != TimeSpan.Zero) |  | ||||||
|             { |  | ||||||
|                 adapter.CacheTimeout = config.GetValue(DataHandlingAdapterExtension.CacheTimeoutProperty); |  | ||||||
|             } |  | ||||||
|             if (config.GetValue(DataHandlingAdapterExtension.CacheTimeoutEnableProperty) is bool v2) |  | ||||||
|             { |  | ||||||
|                 adapter.CacheTimeoutEnable = v2; |  | ||||||
|             } |  | ||||||
|             if (config.GetValue(DataHandlingAdapterExtension.UpdateCacheTimeWhenRevProperty) is bool v3) |  | ||||||
|             { |  | ||||||
|                 adapter.UpdateCacheTimeWhenRev = v3; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         #endregion |  | ||||||
|  |  | ||||||
|         #region 适配器配置 |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/> |  | ||||||
|         /// </summary> |  | ||||||
|         public static readonly DependencyProperty<bool?> CacheTimeoutEnableProperty = DependencyProperty<bool?>.Register("CacheTimeoutEnable", null); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/> |  | ||||||
|         /// </summary> |  | ||||||
|         public static readonly DependencyProperty<TimeSpan> CacheTimeoutProperty = DependencyProperty<TimeSpan>.Register("CacheTimeout", TimeSpan.Zero); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/> |  | ||||||
|         /// </summary> |  | ||||||
|         public static readonly DependencyProperty<int?> MaxPackageSizeProperty = DependencyProperty<int?>.Register("MaxPackageSize", null); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/> |  | ||||||
|         /// </summary> |  | ||||||
|         public static readonly DependencyProperty<bool?> UpdateCacheTimeWhenRevProperty = DependencyProperty<bool?>.Register("UpdateCacheTimeWhenRev", null); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包缓存时长。默认为缺省(<see cref="TimeSpan.Zero"/>)。当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeout"/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="config"></param> |  | ||||||
|         /// <param name="value"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public static TouchSocketConfig SetCacheTimeout(this TouchSocketConfig config, TimeSpan value) |  | ||||||
|         { |  | ||||||
|             config.SetValue(CacheTimeoutProperty, value); |  | ||||||
|             return config; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.CacheTimeoutEnable"/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="config"></param> |  | ||||||
|         /// <param name="value"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public static TouchSocketConfig SetCacheTimeoutEnable(this TouchSocketConfig config, bool value) |  | ||||||
|         { |  | ||||||
|             config.SetValue(CacheTimeoutEnableProperty, value); |  | ||||||
|             return config; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="DataHandlingAdapter.MaxPackageSize"/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="config"></param> |  | ||||||
|         /// <param name="value"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public static TouchSocketConfig SetMaxPackageSize(this TouchSocketConfig config, int value) |  | ||||||
|         { |  | ||||||
|             config.SetValue(MaxPackageSizeProperty, value); |  | ||||||
|             return config; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于<see cref="SingleStreamDataHandlingAdapter.UpdateCacheTimeWhenRev"/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="config"></param> |  | ||||||
|         /// <param name="value"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public static TouchSocketConfig SetUpdateCacheTimeWhenRev(this TouchSocketConfig config, bool value) |  | ||||||
|         { |  | ||||||
|             config.SetValue(UpdateCacheTimeWhenRevProperty, value); |  | ||||||
|             return config; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #endregion 适配器配置 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,94 +0,0 @@ | |||||||
| #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.Dmtp |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// TcpDmtpAdapter |  | ||||||
|     /// </summary> |  | ||||||
|     public class TcpDmtpAdapter : CustomFixedHeaderByteBlockDataHandlingAdapter<DmtpMessage> |  | ||||||
|     { |  | ||||||
|         private SpinLock m_locker = new SpinLock(); |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override bool CanSendRequestInfo => true; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override bool CanSplicingSend => false; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override int HeaderLength => 6; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override DmtpMessage GetInstance() |  | ||||||
|         { |  | ||||||
|             return new DmtpMessage(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void OnReceivedSuccess(DmtpMessage request) |  | ||||||
|         { |  | ||||||
|             request.SafeDispose(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void PreviewSend(IRequestInfo requestInfo) |  | ||||||
|         { |  | ||||||
|             if (!(requestInfo is DmtpMessage message)) |  | ||||||
|             { |  | ||||||
|                 throw new Exception($"无法将{nameof(requestInfo)}转换为{nameof(DmtpMessage)}"); |  | ||||||
|             } |  | ||||||
|             using (var byteBlock = new ByteBlock(message.GetLength())) |  | ||||||
|             { |  | ||||||
|                 message.Build(byteBlock); |  | ||||||
|                 this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes) |  | ||||||
|         { |  | ||||||
|             if (transferBytes.Count == 0) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var length = 0; |  | ||||||
|             foreach (var item in transferBytes) |  | ||||||
|             { |  | ||||||
|                 length += item.Count; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (length > this.MaxPackageSize) |  | ||||||
|             { |  | ||||||
|                 throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var lockTaken = false; |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 this.m_locker.Enter(ref lockTaken); |  | ||||||
|                 foreach (var item in transferBytes) |  | ||||||
|                 { |  | ||||||
|                     this.GoSend(item.Array, item.Offset, item.Count); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 if (lockTaken) |  | ||||||
|                 { |  | ||||||
|                     this.m_locker.Exit(false); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,391 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Dmtp |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// HttpDmtpClient |  | ||||||
|     /// </summary> |  | ||||||
|     public partial class HttpDmtpClient : HttpClientBase, IHttpDmtpClient |  | ||||||
|     { |  | ||||||
|         #region 字段 |  | ||||||
|  |  | ||||||
|         private bool m_allowRoute; |  | ||||||
|         private Func<string, IDmtpActor> m_findDmtpActor; |  | ||||||
|         private DmtpActor m_smtpActor; |  | ||||||
|         private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1); |  | ||||||
|         #endregion 字段 |  | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="IDmtpActor.Id"/> |  | ||||||
|         public string Id => this.DmtpActor.Id; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="IDmtpActor.IsHandshaked"/> |  | ||||||
|         public bool IsHandshaked => this.DmtpActor != null && this.DmtpActor.IsHandshaked; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public IDmtpActor DmtpActor { get => this.m_smtpActor; } |  | ||||||
|  |  | ||||||
|         #region 连接 |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 建立Tcp连接,并且执行握手。 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="timeout"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         /// <exception cref="Exception"></exception> |  | ||||||
|         public override ITcpClient Connect(int timeout = 5000) |  | ||||||
|         { |  | ||||||
|             lock (this.SyncRoot) |  | ||||||
|             { |  | ||||||
|                 if (this.IsHandshaked) |  | ||||||
|                 { |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 if (!this.Online) |  | ||||||
|                 { |  | ||||||
|                     base.Connect(timeout); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 var request = new HttpRequest() |  | ||||||
|                     .SetHost(this.RemoteIPHost.Host); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Connection, "upgrade"); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower()); |  | ||||||
|  |  | ||||||
|                 request.AsMethod(DmtpUtility.Dmtp); |  | ||||||
|                 var response = this.RequestContent(request); |  | ||||||
|                 if (response.StatusCode == 101) |  | ||||||
|                 { |  | ||||||
|                     this.SwitchProtocolToDmtp(); |  | ||||||
|                     this.m_smtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), |  | ||||||
|                         this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), |  | ||||||
|                         timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None); |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     throw new Exception(response.StatusMessage); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public virtual IHttpDmtpClient Connect(CancellationToken cancellationToken, int timeout = 5000) |  | ||||||
|         { |  | ||||||
|             lock (this.SyncRoot) |  | ||||||
|             { |  | ||||||
|                 if (this.IsHandshaked) |  | ||||||
|                 { |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 if (!this.Online) |  | ||||||
|                 { |  | ||||||
|                     base.Connect(timeout); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 var request = new HttpRequest() |  | ||||||
|                     .SetHost(this.RemoteIPHost.Host); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Connection, "upgrade"); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower()); |  | ||||||
|  |  | ||||||
|                 request.AsMethod(DmtpUtility.Dmtp); |  | ||||||
|                 var response = this.RequestContent(request, timeout: timeout, cancellationToken: cancellationToken); |  | ||||||
|                 if (response.StatusCode == 101) |  | ||||||
|                 { |  | ||||||
|                     this.SwitchProtocolToDmtp(); |  | ||||||
|                     this.m_smtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), |  | ||||||
|                         this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), |  | ||||||
|                         timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), cancellationToken); |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     throw new Exception(response.StatusMessage); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 建立Tcp连接,并且执行握手。 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="timeout"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         /// <exception cref="Exception"></exception> |  | ||||||
|         public override async Task<ITcpClient> ConnectAsync(int timeout = 5000) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await this.m_semaphore.WaitAsync(); |  | ||||||
|                 if (this.IsHandshaked) |  | ||||||
|                 { |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 if (!this.Online) |  | ||||||
|                 { |  | ||||||
|                     await base.ConnectAsync(timeout); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 var request = new HttpRequest() |  | ||||||
|                     .SetHost(this.RemoteIPHost.Host); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Connection, "upgrade"); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower()); |  | ||||||
|  |  | ||||||
|                 request.AsMethod(DmtpUtility.Dmtp); |  | ||||||
|                 var response = this.RequestContent(request); |  | ||||||
|                 if (response.StatusCode == 101) |  | ||||||
|                 { |  | ||||||
|                     this.SwitchProtocolToDmtp(); |  | ||||||
|                     await this.m_smtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), |  | ||||||
|                          this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), |  | ||||||
|                          timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None); |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     throw new Exception(response.StatusMessage); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 this.m_semaphore.Release(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public virtual async Task<IHttpDmtpClient> ConnectAsync(CancellationToken cancellationToken, int timeout = 5000) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await this.m_semaphore.WaitAsync(); |  | ||||||
|                 if (this.IsHandshaked) |  | ||||||
|                 { |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 if (!this.Online) |  | ||||||
|                 { |  | ||||||
|                     await base.ConnectAsync(timeout); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 var request = new HttpRequest() |  | ||||||
|                     .SetHost(this.RemoteIPHost.Host); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Connection, "upgrade"); |  | ||||||
|                 request.Headers.Add(HttpHeaders.Upgrade, DmtpUtility.Dmtp.ToLower()); |  | ||||||
|  |  | ||||||
|                 request.AsMethod(DmtpUtility.Dmtp); |  | ||||||
|                 var response = this.RequestContent(request, timeout: timeout, cancellationToken: cancellationToken); |  | ||||||
|                 if (response.StatusCode == 101) |  | ||||||
|                 { |  | ||||||
|                     this.SwitchProtocolToDmtp(); |  | ||||||
|                     await this.m_smtpActor.HandshakeAsync(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty), |  | ||||||
|                          this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty), |  | ||||||
|                          timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), cancellationToken); |  | ||||||
|                     return this; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     throw new Exception(response.StatusMessage); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 this.m_semaphore.Release(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #endregion 连接 |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Dispose(bool disposing) |  | ||||||
|         { |  | ||||||
|             this.DmtpActor.SafeDispose(); |  | ||||||
|             base.Dispose(disposing); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|         { |  | ||||||
|             if (this.Protocol == DmtpUtility.DmtpProtocol && requestInfo is DmtpMessage message) |  | ||||||
|             { |  | ||||||
|                 if (!this.m_smtpActor.InputReceivedData(message)) |  | ||||||
|                 { |  | ||||||
|                     if (this.PluginsManager.Enable) |  | ||||||
|                     { |  | ||||||
|                         this.PluginsManager.Raise(nameof(IDmtpReceivedPlugin.OnDmtpReceived), this, new DmtpMessageEventArgs(message)); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|             return base.HandleReceivedData(byteBlock, requestInfo); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void LoadConfig(TouchSocketConfig config) |  | ||||||
|         { |  | ||||||
|             base.LoadConfig(config); |  | ||||||
|             if (this.Container.IsRegistered(typeof(IDmtpRouteService))) |  | ||||||
|             { |  | ||||||
|                 this.m_allowRoute = true; |  | ||||||
|                 this.m_findDmtpActor = this.Container.Resolve<IDmtpRouteService>().FindDmtpActor; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void OnDisconnected(DisconnectEventArgs e) |  | ||||||
|         { |  | ||||||
|             base.OnDisconnected(e); |  | ||||||
|             this.DmtpActor.Close(false, e.Message); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #region ResetId |  | ||||||
|  |  | ||||||
|         ///<inheritdoc cref="IDmtpActor.ResetId(string)"/> |  | ||||||
|         public void ResetId(string id) |  | ||||||
|         { |  | ||||||
|             this.m_smtpActor.ResetId(id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         ///<inheritdoc cref="IDmtpActor.ResetIdAsync(string)"/> |  | ||||||
|         public Task ResetIdAsync(string newId) |  | ||||||
|         { |  | ||||||
|             return this.m_smtpActor.ResetIdAsync(newId); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #endregion ResetId |  | ||||||
|  |  | ||||||
|         private void SwitchProtocolToDmtp() |  | ||||||
|         { |  | ||||||
|             this.Protocol = DmtpUtility.DmtpProtocol; |  | ||||||
|             this.SetDataHandlingAdapter(new TcpDmtpAdapter()); |  | ||||||
|             this.m_smtpActor = new SealedDmtpActor(this.m_allowRoute) |  | ||||||
|             { |  | ||||||
|                 OutputSend = DmtpActorSend, |  | ||||||
|                 OnRouting = OnDmtpActorRouting, |  | ||||||
|                 OnHandshaking = this.OnDmtpActorHandshaking, |  | ||||||
|                 OnHandshaked = OnDmtpActorHandshaked, |  | ||||||
|                 OnClose = OnDmtpActorClose, |  | ||||||
|                 OnCreateChannel = this.OnDmtpActorCreateChannel, |  | ||||||
|                 Logger = this.Logger, |  | ||||||
|                 Client = this, |  | ||||||
|                 OnFindDmtpActor = this.m_findDmtpActor |  | ||||||
|             }; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #region 内部委托绑定 |  | ||||||
|  |  | ||||||
|         private void OnDmtpActorClose(DmtpActor actor, string msg) |  | ||||||
|         { |  | ||||||
|             base.Close(msg); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void OnDmtpActorCreateChannel(DmtpActor actor, CreateChannelEventArgs e) |  | ||||||
|         { |  | ||||||
|             this.OnCreateChannel(e); |  | ||||||
|             if (e.Handled) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.PluginsManager.Raise(nameof(IDmtpCreateChannelPlugin.OnCreateChannel), this, e); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void OnDmtpActorHandshaked(DmtpActor actor, DmtpVerifyEventArgs e) |  | ||||||
|         { |  | ||||||
|             this.OnHandshaked(e); |  | ||||||
|             if (e.Handled) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(IDmtpHandshakedPlugin.OnDmtpHandshaked), this, e)) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void OnDmtpActorHandshaking(DmtpActor actor, DmtpVerifyEventArgs e) |  | ||||||
|         { |  | ||||||
|             this.OnHandshaking(e); |  | ||||||
|             if (e.Handled) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             this.PluginsManager.Raise(nameof(IDmtpHandshakingPlugin.OnDmtpHandshaking), this, e); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void OnDmtpActorRouting(DmtpActor actor, PackageRouterEventArgs e) |  | ||||||
|         { |  | ||||||
|             this.OnRouting(e); |  | ||||||
|             if (e.Handled) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(IDmtpRoutingPlugin.OnDmtpRouting), this, e)) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void DmtpActorSend(DmtpActor actor, ArraySegment<byte>[] transferBytes) |  | ||||||
|         { |  | ||||||
|             base.Send(transferBytes); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #endregion 内部委托绑定 |  | ||||||
|  |  | ||||||
|         #region 事件触发 |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当创建通道 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="e"></param> |  | ||||||
|         protected virtual void OnCreateChannel(CreateChannelEventArgs e) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 在完成握手连接时 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="e"></param> |  | ||||||
|         protected virtual void OnHandshaked(DmtpVerifyEventArgs e) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 即将握手连接时 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="e">参数</param> |  | ||||||
|         protected virtual void OnHandshaking(DmtpVerifyEventArgs e) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当需要转发路由包时 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="e"></param> |  | ||||||
|         protected virtual void OnRouting(PackageRouterEventArgs e) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #endregion 事件触发 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,245 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Http |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// Http客户端 |  | ||||||
|     /// </summary> |  | ||||||
|     public class HttpClient : HttpClientBase |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// Http客户端基类 |  | ||||||
|     /// </summary> |  | ||||||
|     public class HttpClientBase : TcpClientBase, IHttpClient |  | ||||||
|     { |  | ||||||
|         private readonly object m_requestLocker = new object(); |  | ||||||
|         private readonly WaitData<HttpResponse> m_waitData; |  | ||||||
|         private bool m_getContent; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         public HttpClientBase() |  | ||||||
|         { |  | ||||||
|             this.m_waitData = new WaitData<HttpResponse>(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="timeout"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public override ITcpClient Connect(int timeout = 5000) |  | ||||||
|         { |  | ||||||
|             if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy) |  | ||||||
|             { |  | ||||||
|                 var proxyHost = httpProxy.Host; |  | ||||||
|                 var credential = httpProxy.Credential; |  | ||||||
|                 var remoteHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     this.Config.SetRemoteIPHost(proxyHost); |  | ||||||
|                     base.Connect(timeout); |  | ||||||
|                     var request = new HttpRequest(); |  | ||||||
|                     request.InitHeaders() |  | ||||||
|                         .SetHost(remoteHost.Host) |  | ||||||
|                         .SetUrl(remoteHost.Host, true) |  | ||||||
|                         .AsMethod("CONNECT"); |  | ||||||
|                     var response = this.Request(request, timeout: timeout); |  | ||||||
|                     if (response.IsProxyAuthenticationRequired) |  | ||||||
|                     { |  | ||||||
|                         if (credential is null) |  | ||||||
|                         { |  | ||||||
|                             throw new Exception("未指定代理的凭据。"); |  | ||||||
|                         } |  | ||||||
|                         var authHeader = response.Headers.Get(HttpHeaders.ProxyAuthenticate); |  | ||||||
|                         if (authHeader.IsNullOrEmpty()) |  | ||||||
|                         { |  | ||||||
|                             throw new Exception("未指定代理身份验证质询。"); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         var ares = new AuthenticationChallenge(authHeader, credential); |  | ||||||
|  |  | ||||||
|                         request.Headers.Add(HttpHeaders.ProxyAuthorization, ares.ToString()); |  | ||||||
|                         if (!response.KeepAlive) |  | ||||||
|                         { |  | ||||||
|                             base.Close("代理要求关闭连接,随后重写连接。"); |  | ||||||
|                             base.Connect(timeout); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         response = this.Request(request, timeout: timeout); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     if (response.StatusCode != 200) |  | ||||||
|                     { |  | ||||||
|                         throw new Exception(response.StatusMessage); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 finally |  | ||||||
|                 { |  | ||||||
|                     this.Config.SetRemoteIPHost(remoteHost); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 base.Connect(timeout); |  | ||||||
|             } |  | ||||||
|             return this; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="request"><inheritdoc/></param> |  | ||||||
|         /// <param name="onlyRequest"><inheritdoc/></param> |  | ||||||
|         /// <param name="timeout"><inheritdoc/></param> |  | ||||||
|         /// <param name="cancellationToken"><inheritdoc/></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken cancellationToken = default) |  | ||||||
|         { |  | ||||||
|             lock (this.m_requestLocker) |  | ||||||
|             { |  | ||||||
|                 this.m_getContent = false; |  | ||||||
|                 using (var byteBlock = new ByteBlock()) |  | ||||||
|                 { |  | ||||||
|                     request.Build(byteBlock); |  | ||||||
|  |  | ||||||
|                     this.m_waitData.Reset(); |  | ||||||
|                     this.m_waitData.SetCancellationToken(cancellationToken); |  | ||||||
|  |  | ||||||
|                     this.DefaultSend(byteBlock); |  | ||||||
|                     if (onlyRequest) |  | ||||||
|                     { |  | ||||||
|                         return default; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     switch (this.m_waitData.Wait(timeout)) |  | ||||||
|                     { |  | ||||||
|                         case WaitDataStatus.SetRunning: |  | ||||||
|                             return this.m_waitData.WaitResult; |  | ||||||
|  |  | ||||||
|                         case WaitDataStatus.Overtime: |  | ||||||
|                             throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription()); |  | ||||||
|                         case WaitDataStatus.Canceled: |  | ||||||
|                             return default; |  | ||||||
|  |  | ||||||
|                         case WaitDataStatus.Default: |  | ||||||
|                         case WaitDataStatus.Disposed: |  | ||||||
|                         default: |  | ||||||
|                             throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription()); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="request"></param> |  | ||||||
|         /// <param name="onlyRequest"></param> |  | ||||||
|         /// <param name="timeout"></param> |  | ||||||
|         /// <param name="cancellationToken"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken cancellationToken = default) |  | ||||||
|         { |  | ||||||
|             lock (this.m_requestLocker) |  | ||||||
|             { |  | ||||||
|                 this.m_getContent = true; |  | ||||||
|                 using (var byteBlock = new ByteBlock()) |  | ||||||
|                 { |  | ||||||
|                     request.Build(byteBlock); |  | ||||||
|  |  | ||||||
|                     this.m_waitData.Reset(); |  | ||||||
|                     this.m_waitData.SetCancellationToken(cancellationToken); |  | ||||||
|  |  | ||||||
|                     this.DefaultSend(byteBlock); |  | ||||||
|                     if (onlyRequest) |  | ||||||
|                     { |  | ||||||
|                         return default; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     switch (this.m_waitData.Wait(timeout)) |  | ||||||
|                     { |  | ||||||
|                         case WaitDataStatus.SetRunning: |  | ||||||
|                             return this.m_waitData.WaitResult; |  | ||||||
|  |  | ||||||
|                         case WaitDataStatus.Overtime: |  | ||||||
|                             throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription()); |  | ||||||
|                         case WaitDataStatus.Canceled: |  | ||||||
|                             return default; |  | ||||||
|  |  | ||||||
|                         case WaitDataStatus.Default: |  | ||||||
|                         case WaitDataStatus.Disposed: |  | ||||||
|                         default: |  | ||||||
|                             throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription()); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="disposing"></param> |  | ||||||
|         protected override void Dispose(bool disposing) |  | ||||||
|         { |  | ||||||
|             this.m_waitData?.Dispose(); |  | ||||||
|             base.Dispose(disposing); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="byteBlock"></param> |  | ||||||
|         /// <param name="requestInfo"></param> |  | ||||||
|         protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|         { |  | ||||||
|             if (requestInfo is HttpResponse response) |  | ||||||
|             { |  | ||||||
|                 if (this.m_getContent) |  | ||||||
|                 { |  | ||||||
|                     response.TryGetContent(out _); |  | ||||||
|                 } |  | ||||||
|                 this.m_waitData.Set(response); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="e"></param> |  | ||||||
|         protected override void OnConnecting(ConnectingEventArgs e) |  | ||||||
|         { |  | ||||||
|             this.Protocol = Protocol.Http; |  | ||||||
|             this.SetDataHandlingAdapter(new HttpClientDataHandlingAdapter()); |  | ||||||
|             base.OnConnecting(e); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,93 +0,0 @@ | |||||||
| #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.Threading.Tasks; |  | ||||||
| //using ThingsGateway.Foundation; |  | ||||||
|  |  | ||||||
| //namespace ThingsGateway.Foundation.Http.WebSockets |  | ||||||
| //{ |  | ||||||
| //    public class WebSocket : IWebSocket |  | ||||||
| //    { |  | ||||||
| //        private readonly IHttpClientBase m_client; |  | ||||||
| //        private readonly bool m_isServer; |  | ||||||
|  |  | ||||||
| //        public WebSocket(IHttpClientBase client, bool isServer) |  | ||||||
| //        { |  | ||||||
| //            this.m_client = client; |  | ||||||
| //            this.m_isServer = isServer; |  | ||||||
| //        } |  | ||||||
|  |  | ||||||
| //        public bool IsHandshaked => this.m_client.GetHandshaked(); |  | ||||||
|  |  | ||||||
| //        public void Close(string msg) |  | ||||||
| //        { |  | ||||||
| //            using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg)) |  | ||||||
| //            { |  | ||||||
| //                this.Send(frame); |  | ||||||
| //            } |  | ||||||
| //        } |  | ||||||
|  |  | ||||||
| //        public void Ping() |  | ||||||
| //        { |  | ||||||
| //            using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping }) |  | ||||||
| //            { |  | ||||||
| //                this.Send(frame); |  | ||||||
| //            } |  | ||||||
| //        } |  | ||||||
|  |  | ||||||
| //        public void Pong() |  | ||||||
| //        { |  | ||||||
| //            using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong }) |  | ||||||
| //            { |  | ||||||
| //                this.Send(frame); |  | ||||||
| //            } |  | ||||||
| //        } |  | ||||||
|  |  | ||||||
| //        public void Send(WSDataFrame dataFrame) |  | ||||||
| //        { |  | ||||||
| //            using (var byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) |  | ||||||
| //            { |  | ||||||
| //                if (this.m_isServer) |  | ||||||
| //                { |  | ||||||
| //                    dataFrame.BuildResponse(byteBlock); |  | ||||||
| //                } |  | ||||||
| //                else |  | ||||||
| //                { |  | ||||||
| //                    dataFrame.BuildRequest(byteBlock); |  | ||||||
| //                } |  | ||||||
|  |  | ||||||
| //                this.m_client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); |  | ||||||
| //            } |  | ||||||
| //        } |  | ||||||
|  |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 采用WebSocket协议,发送WS数据。 |  | ||||||
| //        /// </summary> |  | ||||||
| //        /// <param name="dataFrame"></param> |  | ||||||
| //        public Task SendAsync(WSDataFrame dataFrame) |  | ||||||
| //        { |  | ||||||
| //            using (var byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) |  | ||||||
| //            { |  | ||||||
| //                if (this.m_isServer) |  | ||||||
| //                { |  | ||||||
| //                    dataFrame.BuildResponse(byteBlock); |  | ||||||
| //                } |  | ||||||
| //                else |  | ||||||
| //                { |  | ||||||
| //                    dataFrame.BuildRequest(byteBlock); |  | ||||||
| //                } |  | ||||||
|  |  | ||||||
| //                return this.m_client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); |  | ||||||
| //            } |  | ||||||
| //        } |  | ||||||
| //    } |  | ||||||
| //} |  | ||||||
| @@ -1,62 +0,0 @@ | |||||||
| #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; |  | ||||||
| //using System.Collections.Generic; |  | ||||||
| //using System.Linq; |  | ||||||
| //using System.Net.WebSockets; |  | ||||||
| //using System.Text; |  | ||||||
| //using System.Threading.Tasks; |  | ||||||
| //using ThingsGateway.Foundation; |  | ||||||
|  |  | ||||||
| //namespace ThingsGateway.Foundation.Http.WebSockets |  | ||||||
| //{ |  | ||||||
| //    /// <summary> |  | ||||||
| //    /// IWebSocket |  | ||||||
| //    /// </summary> |  | ||||||
| //    public interface IWebSocket |  | ||||||
| //    { |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 表示当前WebSocket是否已经完成连接。 |  | ||||||
| //        /// </summary> |  | ||||||
| //        bool IsHandshaked { get; } |  | ||||||
|  |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 发送Close报文。 |  | ||||||
| //        /// </summary> |  | ||||||
| //        /// <param name="msg"></param> |  | ||||||
| //        void Close(string msg); |  | ||||||
|  |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 发送Ping报文。 |  | ||||||
| //        /// </summary> |  | ||||||
| //        void Ping(); |  | ||||||
|  |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 发送Pong报文。 |  | ||||||
| //        /// </summary> |  | ||||||
| //        void Pong(); |  | ||||||
|  |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/> |  | ||||||
| //        /// </summary> |  | ||||||
| //        /// <param name="dataFrame"></param> |  | ||||||
| //        void Send(WSDataFrame dataFrame); |  | ||||||
|  |  | ||||||
| //        /// <summary> |  | ||||||
| //        /// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/> |  | ||||||
| //        /// </summary> |  | ||||||
| //        /// <param name="dataFrame"></param> |  | ||||||
| //        /// <returns></returns> |  | ||||||
| //        Task SendAsync(WSDataFrame dataFrame); |  | ||||||
| //    } |  | ||||||
| //} |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| 该文件夹下的代码全部来自于ThingsGateway.Foundation |  | ||||||
|  |  | ||||||
| 摘自 ThingsGateway.Foundation [Pages](http://rrqm_home.gitee.io/touchsocket/) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,94 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Rpc |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 代码生成标识 |  | ||||||
|     /// </summary> |  | ||||||
|     [Flags] |  | ||||||
|     public enum CodeGeneratorFlag |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成同步代码(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] |  | ||||||
|         Sync = 1, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成异步代码(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] |  | ||||||
|         Async = 2, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成扩展同步代码 |  | ||||||
|         /// </summary> |  | ||||||
|         ExtensionSync = 4, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成扩展异步代码 |  | ||||||
|         /// </summary> |  | ||||||
|         ExtensionAsync = 8, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 包含接口(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] |  | ||||||
|         IncludeInterface = 16, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 包含实例(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] |  | ||||||
|         IncludeInstance = 32, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 包含扩展(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         [Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)] |  | ||||||
|         IncludeExtension = 64, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成实例类同步代码(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         InstanceSync = 128, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成实例类异步代码(源代码生成无效) |  | ||||||
|         /// </summary> |  | ||||||
|         InstanceAsync = 256, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成接口同步代码 |  | ||||||
|         /// </summary> |  | ||||||
|         InterfaceSync = 512, |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 生成接口异步代码 |  | ||||||
|         /// </summary> |  | ||||||
|         InterfaceAsync = 1024, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,93 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Rpc |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// Rpc异常 |  | ||||||
|     /// </summary> |  | ||||||
|     [Serializable] |  | ||||||
|     public class RpcException : Exception |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         public RpcException() : base() { } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="message"></param> |  | ||||||
|         public RpcException(string message) : base(message) { } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="message"></param> |  | ||||||
|         /// <param name="inner"></param> |  | ||||||
|         public RpcException(string message, System.Exception inner) : base(message, inner) { } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="info"></param> |  | ||||||
|         /// <param name="context"></param> |  | ||||||
|         protected RpcException(System.Runtime.Serialization.SerializationInfo info, |  | ||||||
|             System.Runtime.Serialization.StreamingContext context) : base(info, context) { } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// Rpc调用异常 |  | ||||||
|     /// </summary> |  | ||||||
|     [Serializable] |  | ||||||
|     public class RpcInvokeException : Exception |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         public RpcInvokeException() : base() { } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="message"></param> |  | ||||||
|         public RpcInvokeException(string message) : base(message) { } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="message"></param> |  | ||||||
|         /// <param name="inner"></param> |  | ||||||
|         public RpcInvokeException(string message, System.Exception inner) : base(message, inner) { } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         ///构造函数 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="info"></param> |  | ||||||
|         /// <param name="context"></param> |  | ||||||
|         protected RpcInvokeException(System.Runtime.Serialization.SerializationInfo info, |  | ||||||
|             System.Runtime.Serialization.StreamingContext context) : base(info, context) { } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| #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.Serial; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 串口基接口 |  | ||||||
| /// </summary> |  | ||||||
| public interface ISerial : IDisposable |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 发送缓存区大小。最小值=1024。 |  | ||||||
|     /// </summary> |  | ||||||
|     int SendBufferSize { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 接收缓存区大小。最小值=1024。 |  | ||||||
|     /// </summary> |  | ||||||
|     int ReceiveBufferSize { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 日志记录器 |  | ||||||
|     /// </summary> |  | ||||||
|     ILog Logger { get; set; } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| #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.Serial; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 通讯基类 |  | ||||||
| /// </summary> |  | ||||||
| public abstract class BaseSerial : DependencyObject, ISerial |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 同步根。 |  | ||||||
|     /// </summary> |  | ||||||
|     protected readonly object SyncRoot = new object(); |  | ||||||
|     private int m_receiveBufferSize = 1024 * 64; |  | ||||||
|     private int m_sendBufferSize = 1024 * 64; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public virtual int SendBufferSize |  | ||||||
|     { |  | ||||||
|         get => m_sendBufferSize; |  | ||||||
|         set => m_sendBufferSize = value < 1024 ? 1024 : value; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public virtual int ReceiveBufferSize |  | ||||||
|     { |  | ||||||
|         get => m_receiveBufferSize; |  | ||||||
|         set => m_receiveBufferSize = value < 1024 ? 1024 : value; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public ILog Logger { get; set; } |  | ||||||
| } |  | ||||||
| @@ -1,941 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| using System.IO.Ports; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| /// <inheritdoc cref="SerialSessionBase"/> |  | ||||||
| public class SerialSession : SerialSessionBase |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 接收到数据 |  | ||||||
|     /// </summary> |  | ||||||
|     public ReceivedEventHandler<SerialSession> Received { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 接收数据 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="byteBlock"></param> |  | ||||||
|     /// <param name="requestInfo"></param> |  | ||||||
|     protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         this.Received?.Invoke(this, byteBlock, requestInfo); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 串口管理 |  | ||||||
| /// </summary> |  | ||||||
| public class SerialSessionBase : BaseSerial, ISerialSession |  | ||||||
| { |  | ||||||
|     static readonly Protocol SerialPort = new("SerialSession"); |  | ||||||
|     /// <summary> |  | ||||||
|     /// 构造函数 |  | ||||||
|     /// </summary> |  | ||||||
|     public SerialSessionBase() |  | ||||||
|     { |  | ||||||
|         this.Protocol = SerialPort; |  | ||||||
|         this.m_receiveCounter = new ValueCounter |  | ||||||
|         { |  | ||||||
|             Period = TimeSpan.FromSeconds(1), |  | ||||||
|             OnPeriod = this.OnReceivePeriod |  | ||||||
|         }; |  | ||||||
|         this.m_sendCounter = new ValueCounter |  | ||||||
|         { |  | ||||||
|             Period = TimeSpan.FromSeconds(1), |  | ||||||
|             OnPeriod = this.OnSendPeriod |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     #region 变量 |  | ||||||
|  |  | ||||||
|     private DelaySender m_delaySender; |  | ||||||
|     private long m_bufferRate = 1; |  | ||||||
|     private bool m_online => MainSerialPort?.IsOpen == true; |  | ||||||
|     ValueCounter m_receiveCounter; |  | ||||||
|     ValueCounter m_sendCounter; |  | ||||||
|  |  | ||||||
|     #endregion 变量 |  | ||||||
|  |  | ||||||
|     #region 事件 |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public ConnectedEventHandler<ISerialSession> Connected { get; set; } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public SerialConnectingEventHandler<ISerialSession> Connecting { get; set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public DisconnectEventHandler<ISerialSessionBase> Disconnected { get; set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public DisconnectEventHandler<ISerialSessionBase> Disconnecting { get; set; } |  | ||||||
|  |  | ||||||
|     private void PrivateOnConnected(object o) |  | ||||||
|     { |  | ||||||
|         var e = (ConnectedEventArgs)o; |  | ||||||
|         this.OnConnected(e); |  | ||||||
|         if (e.Handled) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         this.PluginsManager.Raise(nameof(ITcpConnectedPlugin.OnTcpConnected), this, e); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 已经建立Tcp连接 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="e"></param> |  | ||||||
|     protected virtual void OnConnected(ConnectedEventArgs e) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             this.Connected?.Invoke(this, e); |  | ||||||
|         } |  | ||||||
|         catch (System.Exception ex) |  | ||||||
|         { |  | ||||||
|             this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Connected)}中发生错误。", ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void PrivateOnConnecting(SerialConnectingEventArgs e) |  | ||||||
|     { |  | ||||||
|         if (this.CanSetDataHandlingAdapter) |  | ||||||
|         { |  | ||||||
|             this.SetDataHandlingAdapter(this.Config.GetValue(TouchSocketConfigExtension.TcpDataHandlingAdapterProperty).Invoke()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.OnConnecting(e); |  | ||||||
|         if (e.Handled) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         this.PluginsManager.Raise(nameof(ITcpConnectingPlugin.OnTcpConnecting), this, e); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="e"></param> |  | ||||||
|     protected virtual void OnConnecting(SerialConnectingEventArgs e) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             this.Connecting?.Invoke(this, e); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.OnConnecting)}中发生错误。", ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void PrivateOnDisconnected(DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         this.OnDisconnected(e); |  | ||||||
|         if (e.Handled) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         this.PluginsManager.Raise(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 断开连接。在客户端未设置连接状态时,不会触发 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="e"></param> |  | ||||||
|     protected virtual void OnDisconnected(DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             this.Disconnected?.Invoke(this, e); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Disconnected)}中发生错误。", ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void PrivateOnDisconnecting(DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         this.OnDisconnecting(e); |  | ||||||
|         if (e.Handled) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         this.PluginsManager.Raise(nameof(ITcpDisconnectingPlugin.OnTcpDisconnecting), this, e); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 即将断开连接(仅主动断开时有效)。 |  | ||||||
|     /// <para> |  | ||||||
|     /// 当主动调用Close断开时。 |  | ||||||
|     /// </para> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="e"></param> |  | ||||||
|     protected virtual void OnDisconnecting(DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             this.Disconnecting?.Invoke(this, e); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             this.Logger.Log(LogLevel.Error, this, $"在事件{nameof(this.Disconnecting)}中发生错误。", ex); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 事件 |  | ||||||
|  |  | ||||||
|     #region 属性 |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public DateTime LastSendTime => this.m_sendCounter.LastIncrement; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public Func<ByteBlock, bool> OnHandleRawBuffer { get; set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public Func<ByteBlock, IRequestInfo, bool> OnHandleReceivedData { get; set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public IContainer Container { get; private set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public virtual bool CanSetDataHandlingAdapter => true; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public TouchSocketConfig Config { get; private set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public SingleStreamDataHandlingAdapter DataHandlingAdapter { get; private set; } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     public SerialProperty SerialProperty { get; private set; } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public SerialPort MainSerialPort { get; private set; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public bool Online { get => this.m_online; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public bool CanSend => this.m_online; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public IPluginsManager PluginsManager { get; private set; } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public ReceiveType ReceiveType { get; private set; } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public Protocol Protocol { get; set; } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     #endregion 属性 |  | ||||||
|  |  | ||||||
|     #region 断开操作 |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string ToString() |  | ||||||
|     { |  | ||||||
|         return SerialProperty?.ToString(); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public virtual void Close(string msg = TouchSocketCoreUtility.Empty) |  | ||||||
|     { |  | ||||||
|         lock (this.SyncRoot) |  | ||||||
|         { |  | ||||||
|             if (this.m_online) |  | ||||||
|             { |  | ||||||
|                 this.PrivateOnDisconnecting(new DisconnectEventArgs(true, msg)); |  | ||||||
|  |  | ||||||
|                 this.MainSerialPort.TryClose(); |  | ||||||
|  |  | ||||||
|                 this.MainSerialPort.SafeDispose(); |  | ||||||
|                 this.m_delaySender.SafeDispose(); |  | ||||||
|                 this.DataHandlingAdapter.SafeDispose(); |  | ||||||
|                 this.PrivateOnDisconnected(new DisconnectEventArgs(true, msg)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void BreakOut(string msg) |  | ||||||
|     { |  | ||||||
|         lock (this.SyncRoot) |  | ||||||
|         { |  | ||||||
|             if (this.m_online) |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|                 this.MainSerialPort.SafeDispose(); |  | ||||||
|                 this.m_delaySender.SafeDispose(); |  | ||||||
|                 this.DataHandlingAdapter.SafeDispose(); |  | ||||||
|                 this.PrivateOnDisconnected(new DisconnectEventArgs(false, msg)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="disposing"></param> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         lock (this.SyncRoot) |  | ||||||
|         { |  | ||||||
|             if (this.m_online) |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|                 this.MainSerialPort.TryClose(); |  | ||||||
|                 this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); |  | ||||||
|  |  | ||||||
|                 this.MainSerialPort.SafeDispose(); |  | ||||||
|                 this.m_delaySender.SafeDispose(); |  | ||||||
|                 this.DataHandlingAdapter.SafeDispose(); |  | ||||||
|                 this.PluginsManager.SafeDispose(); |  | ||||||
|                 this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 断开操作 |  | ||||||
|  |  | ||||||
|     #region Connect |  | ||||||
|     /// <summary> |  | ||||||
|     /// 打开串口 |  | ||||||
|     /// </summary> |  | ||||||
|     protected void Open() |  | ||||||
|     { |  | ||||||
|         lock (this.SyncRoot) |  | ||||||
|         { |  | ||||||
|             if (this.m_online) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (this.DisposedValue) |  | ||||||
|             { |  | ||||||
|                 throw new ObjectDisposedException(this.GetType().FullName); |  | ||||||
|             } |  | ||||||
|             if (this.Config == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException("配置文件不能为空。"); |  | ||||||
|             } |  | ||||||
|             var serialProperty = this.Config.GetValue(SerialConfigExtension.SerialProperty) ?? throw new ArgumentNullException("串口配置不能为空。"); |  | ||||||
|  |  | ||||||
|             this.MainSerialPort.SafeDispose(); |  | ||||||
|             var serialPort = this.CreateSerial(serialProperty); |  | ||||||
|             var args = new SerialConnectingEventArgs(this.MainSerialPort); |  | ||||||
|             this.PrivateOnConnecting(args); |  | ||||||
|             serialPort.Open(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             this.SetSerialPort(serialPort); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             this.BeginReceive(); |  | ||||||
|             this.PrivateOnConnected(new ConnectedEventArgs()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public virtual ISerialSession Connect() |  | ||||||
|     { |  | ||||||
|         this.Open(); |  | ||||||
|         return this; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public Task<ISerialSession> ConnectAsync() |  | ||||||
|     { |  | ||||||
|         return Task.Run(() => |  | ||||||
|         { |  | ||||||
|             return this.Connect(); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|     #endregion |  | ||||||
|  |  | ||||||
|     private void OnReceivePeriod(long value) |  | ||||||
|     { |  | ||||||
|         this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void OnSendPeriod(long value) |  | ||||||
|     { |  | ||||||
|         this.SendBufferSize = TouchSocketUtility.HitBufferLength(value); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override int ReceiveBufferSize |  | ||||||
|     { |  | ||||||
|         get => base.ReceiveBufferSize; |  | ||||||
|         set |  | ||||||
|         { |  | ||||||
|             base.ReceiveBufferSize = value; |  | ||||||
|             if (this.MainSerialPort != null && !MainSerialPort.IsOpen) |  | ||||||
|             { |  | ||||||
|                 this.MainSerialPort.ReadBufferSize = base.ReceiveBufferSize; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override int SendBufferSize |  | ||||||
|     { |  | ||||||
|         get => base.SendBufferSize; |  | ||||||
|         set |  | ||||||
|         { |  | ||||||
|             base.SendBufferSize = value; |  | ||||||
|             if (this.MainSerialPort != null && !MainSerialPort.IsOpen) |  | ||||||
|             { |  | ||||||
|                 this.MainSerialPort.WriteBufferSize = base.SendBufferSize; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public virtual void SetDataHandlingAdapter(SingleStreamDataHandlingAdapter adapter) |  | ||||||
|     { |  | ||||||
|         if (!this.CanSetDataHandlingAdapter) |  | ||||||
|         { |  | ||||||
|             throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.SetAdapter(adapter); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public ISerialSession Setup(TouchSocketConfig config) |  | ||||||
|     { |  | ||||||
|         if (config == null) |  | ||||||
|         { |  | ||||||
|             throw new ArgumentNullException(nameof(config)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.ThrowIfDisposed(); |  | ||||||
|  |  | ||||||
|         this.BuildConfig(config); |  | ||||||
|  |  | ||||||
|         this.PluginsManager.Raise(nameof(ILoadingConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); |  | ||||||
|         this.LoadConfig(this.Config); |  | ||||||
|         this.PluginsManager.Raise(nameof(ILoadedConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); |  | ||||||
|  |  | ||||||
|         return this; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void BuildConfig(TouchSocketConfig config) |  | ||||||
|     { |  | ||||||
|         this.Config = config; |  | ||||||
|  |  | ||||||
|         if (!(config.GetValue(TouchSocketCoreConfigExtension.ContainerProperty) is IContainer container)) |  | ||||||
|         { |  | ||||||
|             container = new Container(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (!container.IsRegistered(typeof(ILog))) |  | ||||||
|         { |  | ||||||
|             container.RegisterSingleton<ILog, LoggerGroup>(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (!(config.GetValue(TouchSocketCoreConfigExtension.PluginsManagerProperty) is IPluginsManager pluginsManager)) |  | ||||||
|         { |  | ||||||
|             pluginsManager = new PluginsManager(container); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (container.IsRegistered(typeof(IPluginsManager))) |  | ||||||
|         { |  | ||||||
|             pluginsManager = container.Resolve<IPluginsManager>(); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             container.RegisterSingleton<IPluginsManager>(pluginsManager); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (config.GetValue(TouchSocketCoreConfigExtension.ConfigureContainerProperty) is Action<IContainer> actionContainer) |  | ||||||
|         { |  | ||||||
|             actionContainer.Invoke(container); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (config.GetValue(TouchSocketCoreConfigExtension.ConfigurePluginsProperty) is Action<IPluginsManager> actionPluginsManager) |  | ||||||
|         { |  | ||||||
|             pluginsManager.Enable = true; |  | ||||||
|             actionPluginsManager.Invoke(pluginsManager); |  | ||||||
|         } |  | ||||||
|         this.Container = container; |  | ||||||
|         this.PluginsManager = pluginsManager; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         if (this.OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.HandleReceivedData(byteBlock, requestInfo)) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.PluginsManager.Enable) |  | ||||||
|         { |  | ||||||
|             var args = new ReceivedDataEventArgs(byteBlock, requestInfo); |  | ||||||
|             this.PluginsManager.Raise(nameof(ITcpReceivedPlugin.OnTcpReceived), this, args); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 处理已接收到的数据。 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="byteBlock">以二进制流形式传递</param> |  | ||||||
|     /// <param name="requestInfo">以解析的数据对象传递</param> |  | ||||||
|     /// <returns>如果返回<see langword="true"/>则表示数据已被处理,且不会再向下传递。</returns> |  | ||||||
|     protected virtual bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="buffer">数据缓存区</param> |  | ||||||
|     /// <param name="offset">偏移</param> |  | ||||||
|     /// <param name="length">长度</param> |  | ||||||
|     /// <returns>返回值表示是否允许发送</returns> |  | ||||||
|     protected virtual bool HandleSendingData(byte[] buffer, int offset, int length) |  | ||||||
|     { |  | ||||||
|         if (this.PluginsManager.Enable) |  | ||||||
|         { |  | ||||||
|             var args = new SendingEventArgs(buffer, offset, length); |  | ||||||
|             this.PluginsManager.Raise(nameof(ITcpSendingPlugin.OnTcpSending), this, args); |  | ||||||
|             return args.IsPermitOperation; |  | ||||||
|         } |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 加载配置 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="config"></param> |  | ||||||
|     protected virtual void LoadConfig(TouchSocketConfig config) |  | ||||||
|     { |  | ||||||
|         this.SerialProperty = config.GetValue(SerialConfigExtension.SerialProperty); |  | ||||||
|         this.Logger ??= this.Container.Resolve<ILog>(); |  | ||||||
|         this.ReceiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 在延迟发生错误 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="ex"></param> |  | ||||||
|     protected virtual void OnDelaySenderError(Exception ex) |  | ||||||
|     { |  | ||||||
|         this.Logger.Log(LogLevel.Error, this, "发送错误", ex); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 设置适配器,该方法不会检验<see cref="CanSetDataHandlingAdapter"/>的值。 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="adapter"></param> |  | ||||||
|     protected void SetAdapter(SingleStreamDataHandlingAdapter adapter) |  | ||||||
|     { |  | ||||||
|         this.ThrowIfDisposed(); |  | ||||||
|         if (adapter is null) |  | ||||||
|         { |  | ||||||
|             throw new ArgumentNullException(nameof(adapter)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.Config != null) |  | ||||||
|         { |  | ||||||
|             adapter.Config(this.Config); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         adapter.Logger = this.Logger; |  | ||||||
|         adapter.OnLoaded(this); |  | ||||||
|         adapter.ReceivedCallBack = this.PrivateHandleReceivedData; |  | ||||||
|         adapter.SendCallBack = this.DefaultSend; |  | ||||||
|         this.DataHandlingAdapter = adapter; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void BeginReceive() |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         if (this.ReceiveType == ReceiveType.Iocp) |  | ||||||
|         { |  | ||||||
|             SerialReceivedEventArgs eventArgs = new(); |  | ||||||
|             var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize); |  | ||||||
|             byteBlock.SetLength(0); |  | ||||||
|             eventArgs.UserToken = byteBlock; |  | ||||||
|             if (this.MainSerialPort.BytesToRead > 0) |  | ||||||
|             { |  | ||||||
|                 this.ProcessReceived(eventArgs); |  | ||||||
|             } |  | ||||||
|             MainSerialPort.DataReceived += this.EventArgs_Completed; |  | ||||||
|         } |  | ||||||
|         else if (this.ReceiveType == ReceiveType.Bio) |  | ||||||
|         { |  | ||||||
|             new Thread(BeginBio) |  | ||||||
|             { |  | ||||||
|                 IsBackground = true |  | ||||||
|             } |  | ||||||
|             .Start(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     private SerialPort CreateSerial(SerialProperty serialProperty) |  | ||||||
|     { |  | ||||||
|         SerialPort serialPort = new(serialProperty.PortName, serialProperty.BaudRate, serialProperty.Parity, serialProperty.DataBits, serialProperty.StopBits) |  | ||||||
|         { |  | ||||||
|             DtrEnable = true, |  | ||||||
|             RtsEnable = true |  | ||||||
|         }; |  | ||||||
|         return serialPort; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void EventArgs_Completed(object sender, SerialDataReceivedEventArgs e) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             this.m_bufferRate = 1; |  | ||||||
|             SerialReceivedEventArgs eventArgs = new(); |  | ||||||
|             var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength)); |  | ||||||
|             newByteBlock.SetLength(0); |  | ||||||
|             eventArgs.UserToken = newByteBlock; |  | ||||||
|             if (MainSerialPort.BytesToRead > 0) |  | ||||||
|             { |  | ||||||
|                 this.ProcessReceived(eventArgs); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             this.BreakOut(ex.Message); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     private void BeginBio() |  | ||||||
|     { |  | ||||||
|         while (true) |  | ||||||
|         { |  | ||||||
|             var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize); |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 int r = MainSerialPort.Read(byteBlock.Buffer, 0, MainSerialPort.BytesToRead); |  | ||||||
|                 if (r == 0) |  | ||||||
|                 { |  | ||||||
|                     this.BreakOut("远程终端主动关闭"); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 byteBlock.SetLength(r); |  | ||||||
|                 this.HandleBuffer(byteBlock); |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 this.BreakOut(ex.Message); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void ProcessReceived(SerialReceivedEventArgs e) |  | ||||||
|     { |  | ||||||
|         if (!this.m_online) |  | ||||||
|         { |  | ||||||
|             e.UserToken.SafeDispose(); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if (MainSerialPort.BytesToRead > 0) |  | ||||||
|         { |  | ||||||
|             byte[] buffer = new byte[2048]; |  | ||||||
|             var byteBlock = (ByteBlock)e.UserToken; |  | ||||||
|             int num = MainSerialPort.Read(buffer, 0, MainSerialPort.BytesToRead); |  | ||||||
|             byteBlock.Write(buffer, 0, num); |  | ||||||
|             this.HandleBuffer(byteBlock); |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength)); |  | ||||||
|                 newByteBlock.SetLength(num); |  | ||||||
|                 e.UserToken = newByteBlock; |  | ||||||
|  |  | ||||||
|                 if (MainSerialPort.BytesToRead > 0) |  | ||||||
|                 { |  | ||||||
|                     this.m_bufferRate += 2; |  | ||||||
|                     this.ProcessReceived(e); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 e.UserToken.SafeDispose(); |  | ||||||
|                 this.BreakOut(ex.Message); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             e.UserToken.SafeDispose(); |  | ||||||
|             this.BreakOut("远程终端主动关闭"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void SetSerialPort(SerialPort serialPort) |  | ||||||
|     { |  | ||||||
|         if (serialPort == null) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.MainSerialPort = serialPort; |  | ||||||
|         var delaySenderOption = this.Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty); |  | ||||||
|         if (delaySenderOption != null) |  | ||||||
|         { |  | ||||||
|             this.m_delaySender = new DelaySender(delaySenderOption, this.MainSerialPort.AbsoluteSend); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// 处理数据 |  | ||||||
|     /// </summary> |  | ||||||
|     private void HandleBuffer(ByteBlock byteBlock) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             this.m_receiveCounter.Increment(byteBlock.Length); |  | ||||||
|             if (this.OnHandleRawBuffer?.Invoke(byteBlock) == false) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (this.DisposedValue) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (this.PluginsManager.Enable && this.PluginsManager.Raise(nameof(ITcpReceivingPlugin.OnTcpReceiving), this, new ByteBlockEventArgs(byteBlock))) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (this.DataHandlingAdapter == null) |  | ||||||
|             { |  | ||||||
|                 this.Logger.Error(this, TouchSocketResource.NullDataAdapter.GetDescription()); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             this.DataHandlingAdapter.ReceivedInput(byteBlock); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             this.Logger.Log(LogLevel.Error, this, "在处理数据时发生错误", ex); |  | ||||||
|         } |  | ||||||
|         finally |  | ||||||
|         { |  | ||||||
|             byteBlock.Dispose(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #region 发送 |  | ||||||
|  |  | ||||||
|     #region 同步发送 |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="requestInfo"></param> |  | ||||||
|     /// <exception cref="NotConnectedException"></exception> |  | ||||||
|     /// <exception cref="OverlengthException"></exception> |  | ||||||
|     /// <exception cref="Exception"></exception> |  | ||||||
|     public void Send(IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         if (this.DisposedValue) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if (this.DataHandlingAdapter == null) |  | ||||||
|         { |  | ||||||
|             throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription()); |  | ||||||
|         } |  | ||||||
|         if (!this.DataHandlingAdapter.CanSendRequestInfo) |  | ||||||
|         { |  | ||||||
|             throw new NotSupportedException($"当前适配器不支持对象发送。"); |  | ||||||
|         } |  | ||||||
|         this.DataHandlingAdapter.SendInput(requestInfo); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="buffer"><inheritdoc/></param> |  | ||||||
|     /// <param name="offset"><inheritdoc/></param> |  | ||||||
|     /// <param name="length"><inheritdoc/></param> |  | ||||||
|     /// <exception cref="NotConnectedException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="OverlengthException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="Exception"><inheritdoc/></exception> |  | ||||||
|     public virtual void Send(byte[] buffer, int offset, int length) |  | ||||||
|     { |  | ||||||
|         if (this.DataHandlingAdapter == null) |  | ||||||
|         { |  | ||||||
|             throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription()); |  | ||||||
|         } |  | ||||||
|         this.DataHandlingAdapter.SendInput(buffer, offset, length); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="transferBytes"><inheritdoc/></param> |  | ||||||
|     /// <exception cref="NotConnectedException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="OverlengthException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="Exception"><inheritdoc/></exception> |  | ||||||
|     public virtual void Send(IList<ArraySegment<byte>> transferBytes) |  | ||||||
|     { |  | ||||||
|         if (this.DataHandlingAdapter == null) |  | ||||||
|         { |  | ||||||
|             throw new ArgumentNullException(nameof(this.DataHandlingAdapter), TouchSocketResource.NullDataAdapter.GetDescription()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.DataHandlingAdapter.CanSplicingSend) |  | ||||||
|         { |  | ||||||
|             this.DataHandlingAdapter.SendInput(transferBytes); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             var length = 0; |  | ||||||
|             foreach (var item in transferBytes) |  | ||||||
|             { |  | ||||||
|                 length += item.Count; |  | ||||||
|             } |  | ||||||
|             using var byteBlock = new ByteBlock(length); |  | ||||||
|             foreach (var item in transferBytes) |  | ||||||
|             { |  | ||||||
|                 byteBlock.Write(item.Array, item.Offset, item.Count); |  | ||||||
|             } |  | ||||||
|             this.DataHandlingAdapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 同步发送 |  | ||||||
|  |  | ||||||
|     #region 异步发送 |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="buffer"><inheritdoc/></param> |  | ||||||
|     /// <param name="offset"><inheritdoc/></param> |  | ||||||
|     /// <param name="length"><inheritdoc/></param> |  | ||||||
|     /// <exception cref="NotConnectedException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="OverlengthException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="Exception"><inheritdoc/></exception> |  | ||||||
|     public virtual Task SendAsync(byte[] buffer, int offset, int length) |  | ||||||
|     { |  | ||||||
|         return Task.Run(() => |  | ||||||
|         { |  | ||||||
|             this.Send(buffer, offset, length); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="requestInfo"></param> |  | ||||||
|     /// <exception cref="NotConnectedException"></exception> |  | ||||||
|     /// <exception cref="OverlengthException"></exception> |  | ||||||
|     /// <exception cref="Exception"></exception> |  | ||||||
|     public virtual Task SendAsync(IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         return Task.Run(() => |  | ||||||
|         { |  | ||||||
|             this.Send(requestInfo); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="transferBytes"><inheritdoc/></param> |  | ||||||
|     /// <exception cref="NotConnectedException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="OverlengthException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="Exception"><inheritdoc/></exception> |  | ||||||
|     public virtual Task SendAsync(IList<ArraySegment<byte>> transferBytes) |  | ||||||
|     { |  | ||||||
|         return Task.Run(() => |  | ||||||
|         { |  | ||||||
|             this.Send(transferBytes); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 异步发送 |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="buffer"><inheritdoc/></param> |  | ||||||
|     /// <param name="offset"><inheritdoc/></param> |  | ||||||
|     /// <param name="length"><inheritdoc/></param> |  | ||||||
|     /// <exception cref="NotConnectedException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="OverlengthException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="Exception"><inheritdoc/></exception> |  | ||||||
|     public void DefaultSend(byte[] buffer, int offset, int length) |  | ||||||
|     { |  | ||||||
|         if (!this.m_online) |  | ||||||
|         { |  | ||||||
|             throw new NotConnectedException(TouchSocketResource.NotConnected.GetDescription()); |  | ||||||
|         } |  | ||||||
|         if (this.HandleSendingData(buffer, offset, length)) |  | ||||||
|         { |  | ||||||
|             if (this.m_delaySender != null && length < m_delaySender.DelayLength) |  | ||||||
|             { |  | ||||||
|                 this.m_delaySender.Send(QueueDataBytes.CreateNew(buffer, offset, length)); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this.MainSerialPort.AbsoluteSend(buffer, offset, length); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.m_sendCounter.Increment(length); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="buffer"><inheritdoc/></param> |  | ||||||
|     /// <param name="offset"><inheritdoc/></param> |  | ||||||
|     /// <param name="length"><inheritdoc/></param> |  | ||||||
|     /// <exception cref="NotConnectedException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="OverlengthException"><inheritdoc/></exception> |  | ||||||
|     /// <exception cref="Exception"><inheritdoc/></exception> |  | ||||||
|     public Task DefaultSendAsync(byte[] buffer, int offset, int length) |  | ||||||
|     { |  | ||||||
|         return Task.Run(() => |  | ||||||
|         { |  | ||||||
|             this.DefaultSend(buffer, offset, length); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 发送 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,392 +0,0 @@ | |||||||
| #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.Net.Security; |  | ||||||
| using System.Net.Sockets; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Sockets |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// Tcp核心 |  | ||||||
|     /// </summary> |  | ||||||
|     public class TcpCore : SocketAsyncEventArgs, IDisposable |  | ||||||
|     { |  | ||||||
|         private const string m_msg1 = "远程终端主动关闭"; |  | ||||||
|  |  | ||||||
|         #region 字段 |  | ||||||
|  |  | ||||||
|         private long m_bufferRate; |  | ||||||
|         private bool m_disposedValue; |  | ||||||
|         private int m_receiveBufferSize = 64 * 1024; |  | ||||||
|         private ValueCounter m_receiveCounter; |  | ||||||
|         private int m_sendBufferSize = 1024 * 64; |  | ||||||
|         private ValueCounter m_sendCounter; |  | ||||||
|         private Stream m_workStream; |  | ||||||
|  |  | ||||||
|         #endregion 字段 |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 创建一个Tcp核心 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="socket"></param> |  | ||||||
|         public TcpCore(Socket socket) |  | ||||||
|         { |  | ||||||
|             this.Socket = socket; |  | ||||||
|             this.m_receiveCounter = new ValueCounter |  | ||||||
|             { |  | ||||||
|                 Period = TimeSpan.FromSeconds(1), |  | ||||||
|                 OnPeriod = this.OnReceivePeriod |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             this.m_sendCounter = new ValueCounter |  | ||||||
|             { |  | ||||||
|                 Period = TimeSpan.FromSeconds(1), |  | ||||||
|                 OnPeriod = this.OnSendPeriod |  | ||||||
|             }; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 析构函数 |  | ||||||
|         /// </summary> |  | ||||||
|         ~TcpCore() |  | ||||||
|         { |  | ||||||
|             this.Dispose(disposing: false); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当关闭的时候 |  | ||||||
|         /// </summary> |  | ||||||
|         public Action<TcpCore, string> OnClose { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当发生异常的时候 |  | ||||||
|         /// </summary> |  | ||||||
|         public Action<TcpCore, Exception> OnException { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当收到数据的时候 |  | ||||||
|         /// </summary> |  | ||||||
|         public Action<TcpCore, ByteBlock> OnReceived { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 接收缓存池(可以设定初始值,运行时的值会根据流速自动调整) |  | ||||||
|         /// </summary> |  | ||||||
|         public int ReceiveBufferSize |  | ||||||
|         { |  | ||||||
|             get => m_receiveBufferSize; |  | ||||||
|             set |  | ||||||
|             { |  | ||||||
|                 m_receiveBufferSize = value; |  | ||||||
|                 this.Socket.ReceiveBufferSize = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送缓存池(可以设定初始值,运行时的值会根据流速自动调整) |  | ||||||
|         /// </summary> |  | ||||||
|         public int SendBufferSize |  | ||||||
|         { |  | ||||||
|             get => this.m_sendBufferSize; |  | ||||||
|             set |  | ||||||
|             { |  | ||||||
|                 this.m_sendBufferSize = value; |  | ||||||
|                 this.Socket.SendBufferSize = value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Socket |  | ||||||
|         /// </summary> |  | ||||||
|         public Socket Socket { get; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 是否启用了Ssl |  | ||||||
|         /// </summary> |  | ||||||
|         public bool UseSsl { get; private set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 以Ssl服务器模式授权 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="sslOption"></param> |  | ||||||
|         public virtual void Authenticate(ServiceSslOption sslOption) |  | ||||||
|         { |  | ||||||
|             var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false); |  | ||||||
|             sslStream.AuthenticateAsServer(sslOption.Certificate); |  | ||||||
|  |  | ||||||
|             this.m_workStream = sslStream; |  | ||||||
|             this.UseSsl = true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 以Ssl客户端模式授权 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="sslOption"></param> |  | ||||||
|         public virtual void Authenticate(ClientSslOption sslOption) |  | ||||||
|         { |  | ||||||
|             var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false); |  | ||||||
|             if (sslOption.ClientCertificates == null) |  | ||||||
|             { |  | ||||||
|                 sslStream.AuthenticateAsClient(sslOption.TargetHost); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 sslStream.AuthenticateAsClient(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation); |  | ||||||
|             } |  | ||||||
|             this.m_workStream = sslStream; |  | ||||||
|             this.UseSsl = true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 以Ssl服务器模式授权 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="sslOption"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public virtual async Task AuthenticateAsync(ServiceSslOption sslOption) |  | ||||||
|         { |  | ||||||
|             var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false); |  | ||||||
|             await sslStream.AuthenticateAsServerAsync(sslOption.Certificate); |  | ||||||
|  |  | ||||||
|             this.m_workStream = sslStream; |  | ||||||
|             this.UseSsl = true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 以Ssl客户端模式授权 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="sslOption"></param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public virtual async Task AuthenticateAsync(ClientSslOption sslOption) |  | ||||||
|         { |  | ||||||
|             var sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(this.Socket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(this.Socket, false), false); |  | ||||||
|             if (sslOption.ClientCertificates == null) |  | ||||||
|             { |  | ||||||
|                 await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 await sslStream.AuthenticateAsClientAsync(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation); |  | ||||||
|             } |  | ||||||
|             this.m_workStream = sslStream; |  | ||||||
|             this.UseSsl = true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 开始以Iocp方式接收 |  | ||||||
|         /// </summary> |  | ||||||
|         public virtual void BeginIocpReceive() |  | ||||||
|         { |  | ||||||
|             var byteBlock = BytePool.Default.GetByteBlock(this.ReceiveBufferSize); |  | ||||||
|             this.UserToken = byteBlock; |  | ||||||
|             this.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); |  | ||||||
|             if (!this.Socket.ReceiveAsync(this)) |  | ||||||
|             { |  | ||||||
|                 this.ProcessReceived(this); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 开始以Ssl接收。 |  | ||||||
|         /// <para> |  | ||||||
|         /// 注意,使用该方法时,应先完成授权。 |  | ||||||
|         /// </para> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public async Task BeginSslReceive() |  | ||||||
|         { |  | ||||||
|             if (!this.UseSsl) |  | ||||||
|             { |  | ||||||
|                 throw new Exception("请先完成Ssl验证授权"); |  | ||||||
|             } |  | ||||||
|             while (true) |  | ||||||
|             { |  | ||||||
|                 var byteBlock = new ByteBlock(this.ReceiveBufferSize); |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     var r = await Task<int>.Factory.FromAsync(this.m_workStream.BeginRead, this.m_workStream.EndRead, byteBlock.Buffer, 0, byteBlock.Capacity, default); |  | ||||||
|                     if (r == 0) |  | ||||||
|                     { |  | ||||||
|                         this.Close(m_msg1); |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     byteBlock.SetLength(r); |  | ||||||
|                     this.HandleBuffer(byteBlock); |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     byteBlock.Dispose(); |  | ||||||
|                     this.Close(ex.Message); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 释放对象 |  | ||||||
|         /// </summary> |  | ||||||
|         public new void Dispose() |  | ||||||
|         { |  | ||||||
|             // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 |  | ||||||
|             this.Dispose(disposing: true); |  | ||||||
|             GC.SuppressFinalize(this); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送数据。 |  | ||||||
|         /// <para> |  | ||||||
|         /// 内部会根据是否启用Ssl,进行直接发送,还是Ssl发送。 |  | ||||||
|         /// </para> |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer"></param> |  | ||||||
|         /// <param name="offset"></param> |  | ||||||
|         /// <param name="length"></param> |  | ||||||
|         public virtual void Send(byte[] buffer, int offset, int length) |  | ||||||
|         { |  | ||||||
|             if (this.UseSsl) |  | ||||||
|             { |  | ||||||
|                 this.m_workStream.Write(buffer, offset, length); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this.Socket.AbsoluteSend(buffer, offset, length); |  | ||||||
|             } |  | ||||||
|             this.m_sendCounter.Increment(length); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当关闭的时候 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="msg"></param> |  | ||||||
|         protected virtual void Close(string msg) |  | ||||||
|         { |  | ||||||
|             this.OnClose?.Invoke(this, msg); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 释放对象 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="disposing"></param> |  | ||||||
|         protected virtual void Dispose(bool disposing) |  | ||||||
|         { |  | ||||||
|             if (!m_disposedValue) |  | ||||||
|             { |  | ||||||
|                 if (disposing) |  | ||||||
|                 { |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 this.m_disposedValue = true; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             base.Dispose(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当发生异常的时候 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="ex"></param> |  | ||||||
|         protected virtual void Exception(Exception ex) |  | ||||||
|         { |  | ||||||
|             this.OnException?.Invoke(this, ex); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override sealed void OnCompleted(SocketAsyncEventArgs e) |  | ||||||
|         { |  | ||||||
|             if (e.LastOperation == SocketAsyncOperation.Receive) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     this.m_bufferRate = 1; |  | ||||||
|                     this.ProcessReceived(e); |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     e.SafeDispose(); |  | ||||||
|                     this.Close(ex.Message); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 当收到数据的时候 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="byteBlock"></param> |  | ||||||
|         protected virtual void Received(ByteBlock byteBlock) |  | ||||||
|         { |  | ||||||
|             this.OnReceived?.Invoke(this, byteBlock); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void HandleBuffer(ByteBlock byteBlock) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 this.m_receiveCounter.Increment(byteBlock.Length); |  | ||||||
|                 this.Received(byteBlock); |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 this.Exception(ex); |  | ||||||
|             } |  | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 byteBlock.Dispose(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void OnReceivePeriod(long value) |  | ||||||
|         { |  | ||||||
|             this.ReceiveBufferSize = TouchSocketUtility.HitBufferLength(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void OnSendPeriod(long value) |  | ||||||
|         { |  | ||||||
|             this.SendBufferSize = TouchSocketUtility.HitBufferLength(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private void ProcessReceived(SocketAsyncEventArgs e) |  | ||||||
|         { |  | ||||||
|             if (e.SocketError != SocketError.Success) |  | ||||||
|             { |  | ||||||
|                 e.SafeDispose(); |  | ||||||
|                 this.Close(e.SocketError.ToString()); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             else if (e.BytesTransferred > 0) |  | ||||||
|             { |  | ||||||
|                 var byteBlock = (ByteBlock)e.UserToken; |  | ||||||
|                 byteBlock.SetLength(e.BytesTransferred); |  | ||||||
|                 this.HandleBuffer(byteBlock); |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     var newByteBlock = BytePool.Default.GetByteBlock((int)Math.Min(this.ReceiveBufferSize * this.m_bufferRate, TouchSocketUtility.MaxBufferLength)); |  | ||||||
|                     e.UserToken = newByteBlock; |  | ||||||
|                     e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity); |  | ||||||
|  |  | ||||||
|                     if (!this.Socket.ReceiveAsync(e)) |  | ||||||
|                     { |  | ||||||
|                         this.m_bufferRate += 2; |  | ||||||
|                         this.ProcessReceived(e); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     e.SafeDispose(); |  | ||||||
|                     this.Close(ex.Message); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 e.SafeDispose(); |  | ||||||
|                 this.Close(m_msg1); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,88 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| using System.Net; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 显示信息 |  | ||||||
| /// </summary> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="e"></param> |  | ||||||
| public delegate void MessageEventHandler<TClient>(TClient client, MsgPermitEventArgs e); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 普通通知 |  | ||||||
| /// </summary> |  | ||||||
| /// <typeparam name="TClient"></typeparam> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="e"></param> |  | ||||||
| public delegate void TouchSocketEventHandler<TClient>(TClient client, PluginEventArgs e); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// Id修改通知 |  | ||||||
| /// </summary> |  | ||||||
| /// <typeparam name="TClient"></typeparam> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="e"></param> |  | ||||||
| public delegate void IdChangedEventHandler<TClient>(TClient client, IdChangedEventArgs e); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// Connecting |  | ||||||
| /// </summary> |  | ||||||
| /// <typeparam name="TClient"></typeparam> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="e"></param> |  | ||||||
| public delegate void ConnectingEventHandler<TClient>(TClient client, ConnectingEventArgs e); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// Connected |  | ||||||
| /// </summary> |  | ||||||
| /// <typeparam name="TClient"></typeparam> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="e"></param> |  | ||||||
| public delegate void ConnectedEventHandler<TClient>(TClient client, ConnectedEventArgs e); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 客户端断开连接 |  | ||||||
| /// </summary> |  | ||||||
| /// <typeparam name="TClient"></typeparam> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="e"></param> |  | ||||||
| public delegate void DisconnectEventHandler<TClient>(TClient client, DisconnectEventArgs e); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 接收数据 |  | ||||||
| /// </summary> |  | ||||||
| /// <param name="client"></param> |  | ||||||
| /// <param name="byteBlock"></param> |  | ||||||
| /// <param name="requestInfo"></param> |  | ||||||
| public delegate void ReceivedEventHandler<TClient>(TClient client, ByteBlock byteBlock, IRequestInfo requestInfo); |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// UDP接收 |  | ||||||
| /// </summary> |  | ||||||
| /// <param name="endpoint"></param> |  | ||||||
| /// <param name="byteBlock"></param> |  | ||||||
| /// <param name="requestInfo"></param> |  | ||||||
| public delegate void UdpReceivedEventHandler(EndPoint endpoint, ByteBlock byteBlock, IRequestInfo requestInfo); |  | ||||||
| @@ -1,109 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Sockets |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 发送等待接口 |  | ||||||
|     /// </summary> |  | ||||||
|     public interface IWaitSender : ISenderBase |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送字节流 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="offset">偏移</param> |  | ||||||
|         /// <param name="length">长度</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送字节流 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送流中的有效数据 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="byteBlock">数据块载体</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 异步发送 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="offset">偏移</param> |  | ||||||
|         /// <param name="length">长度</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 异步发送 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         Task<byte[]> SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 异步发送 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="byteBlock">数据块载体</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         Task<byte[]> SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,119 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |  | ||||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 |  | ||||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home |  | ||||||
| //  Github源代码仓库:https://github.com/RRQM |  | ||||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ |  | ||||||
| //  交流QQ群:234762506 |  | ||||||
| //  感谢您的下载和使用 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Sockets |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 等待型客户端。 |  | ||||||
|     /// </summary> |  | ||||||
|     public interface IWaitingClient<TClient> : IWaitSender, IDisposable where TClient : IClient, IDefaultSender, ISender |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// 等待设置。 |  | ||||||
|         /// </summary> |  | ||||||
|         public WaitingOptions WaitingOptions { get; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 客户端终端 |  | ||||||
|         /// </summary> |  | ||||||
|         TClient Client { get; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送字节流 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="offset">偏移</param> |  | ||||||
|         /// <param name="length">长度</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送字节流 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 发送流中的有效数据 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="byteBlock">数据块载体</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 异步发送 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="offset">偏移</param> |  | ||||||
|         /// <param name="length">长度</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 异步发送 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="buffer">数据缓存区</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 异步发送 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="byteBlock">数据块载体</param> |  | ||||||
|         /// <param name="timeout">超时时间</param> |  | ||||||
|         /// <param name="cancellationToken">取消令箭</param> |  | ||||||
|         /// <exception cref="NotConnectedException">客户端没有连接</exception> |  | ||||||
|         /// <exception cref="OverlengthException">发送数据超长</exception> |  | ||||||
|         /// <exception cref="Exception">其他异常</exception> |  | ||||||
|         /// <returns>返回的数据</returns> |  | ||||||
|         Task<ResponsedData> SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,362 +0,0 @@ | |||||||
| #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.Sockets; |  | ||||||
|  |  | ||||||
| internal class WaitingClient<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender |  | ||||||
| { |  | ||||||
|     private readonly Func<ResponsedData, bool> m_func; |  | ||||||
|     private readonly EasyLock easyLock = new(); |  | ||||||
|     private readonly WaitData<ResponsedData> m_waitData = new(); |  | ||||||
|     private readonly WaitDataAsync<ResponsedData> m_waitDataAsync = new(); |  | ||||||
|  |  | ||||||
|     private volatile bool m_breaked; |  | ||||||
|  |  | ||||||
|     public WaitingClient(TClient client, WaitingOptions waitingOptions, Func<ResponsedData, bool> func) |  | ||||||
|     { |  | ||||||
|         this.Client = client ?? throw new ArgumentNullException(nameof(client)); |  | ||||||
|         this.WaitingOptions = waitingOptions; |  | ||||||
|         this.m_func = func; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public WaitingClient(TClient client, WaitingOptions waitingOptions) |  | ||||||
|     { |  | ||||||
|         this.Client = client ?? throw new ArgumentNullException(nameof(client)); |  | ||||||
|         this.WaitingOptions = waitingOptions; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public bool CanSend |  | ||||||
|     { |  | ||||||
|         get |  | ||||||
|         { |  | ||||||
|             return this.Client is ITcpClientBase tcpClient ? tcpClient.CanSend : this.Client is IUdpSession; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public TClient Client { get; private set; } |  | ||||||
|  |  | ||||||
|     public WaitingOptions WaitingOptions { get; set; } |  | ||||||
|  |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         this.Client = default; |  | ||||||
|         this.m_waitData.SafeDispose(); |  | ||||||
|         this.m_waitDataAsync.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void Cancel() |  | ||||||
|     { |  | ||||||
|         this.m_waitData.Cancel(); |  | ||||||
|         this.m_waitDataAsync.Cancel(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         this.m_breaked = true; |  | ||||||
|         this.Cancel(); |  | ||||||
|     } |  | ||||||
|     private void OnSerialSessionDisconnected(ISerialSessionBase client, DisconnectEventArgs e) |  | ||||||
|     { |  | ||||||
|         this.m_breaked = true; |  | ||||||
|         this.Cancel(); |  | ||||||
|     } |  | ||||||
|     private bool OnHandleRawBuffer(ByteBlock byteBlock) |  | ||||||
|     { |  | ||||||
|         var responsedData = new ResponsedData(byteBlock.ToArray(), null, true); |  | ||||||
|         if (this.m_func == null || this.m_func.Invoke(responsedData)) |  | ||||||
|         { |  | ||||||
|             return !this.Set(responsedData); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private bool OnHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) |  | ||||||
|     { |  | ||||||
|         ResponsedData responsedData; |  | ||||||
|         if (byteBlock != null) |  | ||||||
|         { |  | ||||||
|             responsedData = new ResponsedData(byteBlock.ToArray(), requestInfo, false); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             responsedData = new ResponsedData(null, requestInfo, false); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.m_func == null || this.m_func.Invoke(responsedData)) |  | ||||||
|         { |  | ||||||
|             return !this.Set(responsedData); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void Reset() |  | ||||||
|     { |  | ||||||
|         this.m_waitData.Reset(); |  | ||||||
|         this.m_waitDataAsync.Reset(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #region 同步Response |  | ||||||
|  |  | ||||||
|     public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             easyLock.Wait(); |  | ||||||
|             this.m_breaked = false; |  | ||||||
|             this.Reset(); |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) |  | ||||||
|             { |  | ||||||
|                 tcpClient.Disconnected += this.OnDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession) |  | ||||||
|             { |  | ||||||
|                 serialSession.Disconnected += this.OnSerialSessionDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleReceivedData += this.OnHandleReceivedData; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleRawBuffer += this.OnHandleRawBuffer; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session) |  | ||||||
|             { |  | ||||||
|                 if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) |  | ||||||
|                 { |  | ||||||
|                     session.Send(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     session.DefaultSend(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) |  | ||||||
|                 { |  | ||||||
|                     this.Client.Send(buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     this.Client.DefaultSend(buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.m_waitData.SetCancellationToken(cancellationToken); |  | ||||||
|             switch (this.m_waitData.Wait(timeout)) |  | ||||||
|             { |  | ||||||
|                 case WaitDataStatus.SetRunning: |  | ||||||
|                     return this.m_waitData.WaitResult; |  | ||||||
|  |  | ||||||
|                 case WaitDataStatus.Overtime: |  | ||||||
|                     throw new TimeoutException(); |  | ||||||
|                 case WaitDataStatus.Canceled: |  | ||||||
|                     { |  | ||||||
|                         return this.WaitingOptions.ThrowBreakException && this.m_breaked ? throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。") : (ResponsedData)default; |  | ||||||
|                     } |  | ||||||
|                 case WaitDataStatus.Default: |  | ||||||
|                 case WaitDataStatus.Disposed: |  | ||||||
|                 default: |  | ||||||
|                     throw new Exception("未知错误"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         finally |  | ||||||
|         { |  | ||||||
|             easyLock.Release(); |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) |  | ||||||
|             { |  | ||||||
|                 tcpClient.Disconnected -= this.OnDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession) |  | ||||||
|             { |  | ||||||
|                 serialSession.Disconnected -= this.OnSerialSessionDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleReceivedData -= this.OnHandleReceivedData; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleRawBuffer -= this.OnHandleRawBuffer; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenResponse(buffer, 0, buffer.Length, timeout, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 同步Response |  | ||||||
|  |  | ||||||
|     #region Response异步 |  | ||||||
|  |  | ||||||
|     public async Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             await easyLock.WaitAsync(); |  | ||||||
|             this.m_breaked = false; |  | ||||||
|             this.Reset(); |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) |  | ||||||
|             { |  | ||||||
|                 tcpClient.Disconnected += this.OnDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession) |  | ||||||
|             { |  | ||||||
|                 serialSession.Disconnected += this.OnSerialSessionDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleReceivedData += this.OnHandleReceivedData; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleRawBuffer += this.OnHandleRawBuffer; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (this.WaitingOptions.RemoteIPHost != null && this.Client is IUdpSession session) |  | ||||||
|             { |  | ||||||
|                 if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) |  | ||||||
|                 { |  | ||||||
|                     session.Send(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     session.DefaultSend(this.WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) |  | ||||||
|                 { |  | ||||||
|                     this.Client.Send(buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     this.Client.DefaultSend(buffer, offset, length); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.m_waitDataAsync.SetCancellationToken(cancellationToken); |  | ||||||
|             switch (await this.m_waitDataAsync.WaitAsync(timeout)) |  | ||||||
|             { |  | ||||||
|                 case WaitDataStatus.SetRunning: |  | ||||||
|                     return this.m_waitData.WaitResult; |  | ||||||
|  |  | ||||||
|                 case WaitDataStatus.Overtime: |  | ||||||
|                     throw new TimeoutException(); |  | ||||||
|                 case WaitDataStatus.Canceled: |  | ||||||
|                     { |  | ||||||
|                         return this.WaitingOptions.ThrowBreakException && this.m_breaked ? throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。") : (ResponsedData)default; |  | ||||||
|                     } |  | ||||||
|                 case WaitDataStatus.Default: |  | ||||||
|                 case WaitDataStatus.Disposed: |  | ||||||
|                 default: |  | ||||||
|                     throw new Exception("未知错误"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         finally |  | ||||||
|         { |  | ||||||
|             easyLock.Release(); |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) |  | ||||||
|             { |  | ||||||
|                 tcpClient.Disconnected -= this.OnDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.BreakTrigger && this.Client is ISerialSessionBase serialSession) |  | ||||||
|             { |  | ||||||
|                 serialSession.Disconnected -= this.OnSerialSessionDisconnected; |  | ||||||
|             } |  | ||||||
|             if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleReceivedData -= this.OnHandleReceivedData; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this.Client.OnHandleRawBuffer -= this.OnHandleRawBuffer; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Task<ResponsedData> SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion Response异步 |  | ||||||
|  |  | ||||||
|     #region 字节同步 |  | ||||||
|  |  | ||||||
|     public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenResponse(buffer, offset, length, timeout, cancellationToken).Data; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenReturn(buffer, 0, buffer.Length, timeout, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return this.SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 字节同步 |  | ||||||
|  |  | ||||||
|     #region 字节异步 |  | ||||||
|  |  | ||||||
|     public async Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return (await this.SendThenResponseAsync(buffer, offset, length, timeout, cancellationToken)).Data; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public async Task<byte[]> SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return (await this.SendThenResponseAsync(buffer, 0, buffer.Length, timeout, cancellationToken)).Data; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public async Task<byte[]> SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken cancellationToken = default) |  | ||||||
|     { |  | ||||||
|         return (await this.SendThenResponseAsync(byteBlock.Buffer, 0, byteBlock.Len, timeout, cancellationToken)).Data; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #endregion 字节异步 |  | ||||||
|  |  | ||||||
|     private bool Set(ResponsedData responsedData) |  | ||||||
|     { |  | ||||||
|         this.m_waitData.Set(responsedData); |  | ||||||
|         this.m_waitDataAsync.Set(responsedData); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,45 +0,0 @@ | |||||||
| #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.Sockets; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// WaitingClientExtensions |  | ||||||
| /// </summary> |  | ||||||
| public static class WaitingClientExtension |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// 获取筛选条件的可等待的客户端。 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <typeparam name="TClient"></typeparam> |  | ||||||
|     /// <param name="client"></param> |  | ||||||
|     /// <param name="waitingOptions"></param> |  | ||||||
|     /// <param name="func">当条件成立时返回</param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static IWaitingClient<TClient> GetWaitingClientEx<TClient>(this TClient client, WaitingOptions waitingOptions, Func<ResponsedData, bool> func) where TClient : IClient, IDefaultSender, ISender |  | ||||||
|     { |  | ||||||
|         return new WaitingClient<TClient>(client, waitingOptions, func); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 获取可等待的客户端。 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <typeparam name="TClient"></typeparam> |  | ||||||
|     /// <param name="client"></param> |  | ||||||
|     /// <param name="waitingOptions"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public static IWaitingClient<TClient> GetWaitingClientEx<TClient>(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, IDefaultSender, ISender |  | ||||||
|     { |  | ||||||
|         var waitingClient = new WaitingClient<TClient>(client, waitingOptions); |  | ||||||
|         return waitingClient; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,111 +0,0 @@ | |||||||
| #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.Plugin.DLT645; |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public class DLT645_2007 : CollectBase |  | ||||||
| { |  | ||||||
|     private readonly DLT645_2007Property driverPropertys = new(); |  | ||||||
|     private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007 _plc; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(DLT645_2007DebugPage); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     public override bool IsSupportRequest => true; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         await _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.SerialSession?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, 0); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <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, |  | ||||||
|             }) |  | ||||||
|                 ; |  | ||||||
|             client = new SerialSession(); |  | ||||||
|             ((SerialSession)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((SerialSession)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 cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,103 +0,0 @@ | |||||||
| #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.Plugin.DLT645; |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public class DLT645_2007OverTcp : CollectBase |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private readonly DLT645_2007OverTcpProperty driverPropertys = new(); |  | ||||||
|     private ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp _plc; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(DLT645_2007OverTcpDebugPage); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsSupportRequest => true; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         await _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.TcpClient?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, 0); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|     { |  | ||||||
|         if (client == null) |  | ||||||
|         { |  | ||||||
|             FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                 ; |  | ||||||
|             client = new TcpClient(); |  | ||||||
|             ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((TcpClient)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 cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @using System.Net.Http |  | ||||||
| @using Microsoft.AspNetCore.Components.Forms |  | ||||||
| @using Microsoft.AspNetCore.Components.Routing |  | ||||||
| @using Microsoft.AspNetCore.Components.Web |  | ||||||
| @using Microsoft.AspNetCore.Components.Web.Virtualization |  | ||||||
| @using Microsoft.JSInterop |  | ||||||
| @using BlazorComponent |  | ||||||
| @using Masa.Blazor |  | ||||||
| @using Masa.Blazor.Presets |  | ||||||
| @using System.Net.Http.Json |  | ||||||
| @using System.IO; |  | ||||||
| @using System.Text.Json; |  | ||||||
| @using System.Reflection; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Components; |  | ||||||
| @using ThingsGateway.Admin.Core; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension.String; |  | ||||||
| @using ThingsGateway.Admin.Application; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Core; |  | ||||||
| @using ThingsGateway.Gateway.Application; |  | ||||||
| @using ThingsGateway.Gateway.Core; |  | ||||||
| @@ -1,413 +0,0 @@ | |||||||
| #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 Confluent.Kafka; |  | ||||||
|  |  | ||||||
| using Mapster; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Kafka; |  | ||||||
|  |  | ||||||
| using Furion; |  | ||||||
|  |  | ||||||
| using System; |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Linq; |  | ||||||
| using System.Runtime.InteropServices; |  | ||||||
| using System.Threading; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// Kafka消息生产 |  | ||||||
| /// </summary> |  | ||||||
| public class KafkaProducer : UpLoadBase |  | ||||||
| { |  | ||||||
|     private readonly ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new(); |  | ||||||
|     private readonly ConcurrentQueue<VariableData> _collectVariableRunTimes = new(); |  | ||||||
|     private readonly KafkaProducerProperty driverPropertys = new(); |  | ||||||
|     private readonly KafkaProducerVariableProperty variablePropertys = new(); |  | ||||||
|     private GlobalDeviceData _globalDeviceData; |  | ||||||
|     private List<DeviceVariableRunTime> _uploadVariables = new(); |  | ||||||
|     private bool isSuccess = true; |  | ||||||
|     private IProducer<Null, string> producer; |  | ||||||
|     private ProducerBuilder<Null, string> producerBuilder; |  | ||||||
|     private ProducerConfig producerconfig; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => null; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override DriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|     private TimerTick exVariableTimerTick; |  | ||||||
|     private TimerTick exDeviceTimerTick; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var varList = _collectVariableRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (varList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                     var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                     foreach (var item in varData) |  | ||||||
|                     { |  | ||||||
|                         try |  | ||||||
|                         { |  | ||||||
|                             if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                             { |  | ||||||
|                                 await KafKaUp(driverPropertys.VariableTopic, item.ToJsonString(), cancellationToken); |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         catch (Exception ex) |  | ||||||
|                         { |  | ||||||
|                             LogMessage.LogWarning(ex, ToString()); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                     if (isSuccess) |  | ||||||
|                         producer.Flush(cancellationToken); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exVariableTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         var varList = _uploadVariables.Adapt<List<VariableData>>(); |  | ||||||
|                         if (varList?.Count != 0) |  | ||||||
|                         { |  | ||||||
|                             //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                             var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                             foreach (var item in varData) |  | ||||||
|                             { |  | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                     { |  | ||||||
|                                         await KafKaUp(driverPropertys.VariableTopic, item.ToJsonString(), cancellationToken); |  | ||||||
|                                     } |  | ||||||
|                                     else |  | ||||||
|                                     { |  | ||||||
|                                         break; |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                                 catch (Exception ex) |  | ||||||
|                                 { |  | ||||||
|                                     LogMessage.LogWarning(ex, ToString()); |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             if (isSuccess) |  | ||||||
|                                 producer.Flush(cancellationToken); |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var devList = _collectDeviceRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (devList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                     var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                     foreach (var item in devData) |  | ||||||
|                     { |  | ||||||
|                         try |  | ||||||
|                         { |  | ||||||
|                             if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                             { |  | ||||||
|                                 await KafKaUp(driverPropertys.DeviceTopic, item.ToJsonString(), cancellationToken); |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         catch (Exception ex) |  | ||||||
|                         { |  | ||||||
|                             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     if (isSuccess) |  | ||||||
|                         producer.Flush(cancellationToken); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exDeviceTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     var devList = _collectDevice.Adapt<List<DeviceData>>(); |  | ||||||
|                     if (devList?.Count != 0) |  | ||||||
|                     { |  | ||||||
|                         //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                         var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                         foreach (var item in devData) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                 { |  | ||||||
|                                     await KafKaUp(driverPropertys.DeviceTopic, item.ToJsonString(), cancellationToken); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         if (isSuccess) |  | ||||||
|                             producer.Flush(cancellationToken); |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override bool IsConnected() => isSuccess; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _collectDevice.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange -= DeviceStatusChange; |  | ||||||
|         }); |  | ||||||
|         _uploadVariables?.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange -= VariableValueChange; |  | ||||||
|         }); |  | ||||||
|         producer?.Dispose(); |  | ||||||
|         _uploadVariables = null; |  | ||||||
|         _collectDeviceRunTimes.Clear(); |  | ||||||
|         _collectVariableRunTimes.Clear(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     private List<CollectDeviceRunTime> _collectDevice; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 初始化 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="device"></param> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         #region Kafka 生产者 |  | ||||||
|         //1、生产者配置 |  | ||||||
|         producerconfig = new ProducerConfig |  | ||||||
|         { |  | ||||||
|             BootstrapServers = driverPropertys.BootStrapServers, |  | ||||||
|             ClientId = driverPropertys.ClientId, |  | ||||||
|         }; |  | ||||||
|         //2、创建生产者 |  | ||||||
|         producerBuilder = new ProducerBuilder<Null, string>(producerconfig); |  | ||||||
|         //3、错误日志监视 |  | ||||||
|         producerBuilder.SetErrorHandler((p, msg) => |  | ||||||
|         { |  | ||||||
|             isSuccess = false; |  | ||||||
|             LogMessage?.LogWarning(msg.Reason); |  | ||||||
|         }); |  | ||||||
|         //kafka |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             producer = producerBuilder.Build(); |  | ||||||
|         } |  | ||||||
|         catch (DllNotFoundException) |  | ||||||
|         { |  | ||||||
|             if (!Library.IsLoaded) |  | ||||||
|             { |  | ||||||
|                 string fileEx = ".dll"; |  | ||||||
|                 string osStr = "win-"; |  | ||||||
|                 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |  | ||||||
|                 { |  | ||||||
|                     osStr = "win-"; |  | ||||||
|                     fileEx = ".dll"; |  | ||||||
|                 } |  | ||||||
|                 else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |  | ||||||
|                 { |  | ||||||
|                     osStr = "linux-"; |  | ||||||
|                     fileEx = ".so"; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|  |  | ||||||
|                     osStr = "osx-"; |  | ||||||
|                     fileEx = ".dylib"; |  | ||||||
|                 } |  | ||||||
|                 osStr += RuntimeInformation.ProcessArchitecture.ToString().ToLower(); |  | ||||||
|  |  | ||||||
|                 var pathToLibrd = System.IO.Path.Combine(AppContext.BaseDirectory, "Plugins", "ThingsGateway.Plugin.Kafka", "runtimes", osStr, "native", $"librdkafka{fileEx}"); |  | ||||||
|                 Library.Load(pathToLibrd); |  | ||||||
|             } |  | ||||||
|             producer = producerBuilder.Build(); |  | ||||||
|         } |  | ||||||
|         #endregion |  | ||||||
|  |  | ||||||
|         _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|  |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|            .Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue()).ToList(); |  | ||||||
|  |  | ||||||
|         _uploadVariables = tags; |  | ||||||
|  |  | ||||||
|         _collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList(); |  | ||||||
|  |  | ||||||
|         _collectDevice.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange += DeviceStatusChange; |  | ||||||
|         }); |  | ||||||
|         _uploadVariables.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange += VariableValueChange; |  | ||||||
|         }); |  | ||||||
|         if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000; |  | ||||||
|         exVariableTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|         exDeviceTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task KafKaUp(string topic, string payLoad, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             using CancellationTokenSource cancellationTokenSource = new(); |  | ||||||
|             using CancellationTokenSource stoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, cancellationToken); |  | ||||||
|             Task<DeliveryResult<Null, string>> resultTask = producer.ProduceAsync(topic, new Message<Null, string> { Value = payLoad }, stoppingToken.Token); |  | ||||||
|             var timeOutResult = await Task.WhenAny(resultTask, Task.Delay(driverPropertys.TimeOut, stoppingToken.Token)); |  | ||||||
|             if (timeOutResult == resultTask) |  | ||||||
|             { |  | ||||||
|                 var result = (timeOutResult as Task<DeliveryResult<Null, string>>).Result; |  | ||||||
|                 if (result.Status != PersistenceStatus.Persisted) |  | ||||||
|                 { |  | ||||||
|                     isSuccess = false; |  | ||||||
|                     await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     isSuccess = true; |  | ||||||
|                     //连接成功时补发缓存数据 |  | ||||||
|                     var cacheData = await CacheDb.GetCacheData(); |  | ||||||
|                     foreach (var item in cacheData) |  | ||||||
|                     { |  | ||||||
|                         var cacheResult = await producer.ProduceAsync(item.Topic, new Message<Null, string> { Value = item.CacheStr }, stoppingToken.Token); |  | ||||||
|  |  | ||||||
|                         if (cacheResult.Status == PersistenceStatus.Persisted) |  | ||||||
|                         { |  | ||||||
|                             LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}"); |  | ||||||
|  |  | ||||||
|                             await CacheDb.DeleteCacheData(item.Id); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{topic}{Environment.NewLine}负载:{payLoad}"); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 isSuccess = false; |  | ||||||
|                 stoppingToken.Cancel(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|             await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,108 +0,0 @@ | |||||||
| #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.Plugin.Modbus; |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public class ModbusRtu : CollectBase |  | ||||||
| { |  | ||||||
|     private readonly ModbusRtuProperty driverPropertys = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu _plc; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusRtuDebugPage); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <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 cancellationToken) |  | ||||||
|     { |  | ||||||
|         await _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <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?.SerialSession?.CanSend == true; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <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, |  | ||||||
|             }) |  | ||||||
|                 ; |  | ||||||
|             client = new SerialSession(); |  | ||||||
|             ((SerialSession)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((SerialSession)client) |  | ||||||
|         { |  | ||||||
|             Crc16CheckEnable = driverPropertys.Crc16CheckEnable, |  | ||||||
|             FrameTime = driverPropertys.FrameTime, |  | ||||||
|             CacheTimeout = driverPropertys.CacheTimeout, |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             TimeOut = driverPropertys.TimeOut |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,98 +0,0 @@ | |||||||
| #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.Plugin.Modbus; |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public class ModbusRtuOverTcp : CollectBase |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private readonly ModbusRtuOverTcpProperty driverPropertys = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp _plc; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusRtuOverTcpDebugPage); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     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 cancellationToken) |  | ||||||
|     { |  | ||||||
|         await _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.TcpClient?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|     { |  | ||||||
|         if (client == null) |  | ||||||
|         { |  | ||||||
|             FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                 ; |  | ||||||
|             client = new TcpClient(); |  | ||||||
|             ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((TcpClient)client) |  | ||||||
|         { |  | ||||||
|             Crc16CheckEnable = driverPropertys.Crc16CheckEnable, |  | ||||||
|             FrameTime = driverPropertys.FrameTime, |  | ||||||
|             CacheTimeout = driverPropertys.CacheTimeout, |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             TimeOut = driverPropertys.TimeOut |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,102 +0,0 @@ | |||||||
| #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.Plugin.Modbus; |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusRtuOverUdp : CollectBase |  | ||||||
| { |  | ||||||
|     private readonly ModbusRtuOverUdpProperty driverPropertys = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp _plc; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusRtuOverUdpDebugPage); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     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 Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return _plc.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.UdpSession?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|     { |  | ||||||
|         if (client == null) |  | ||||||
|         { |  | ||||||
|             FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                 .SetBindIPHost(new IPHost(0)) |  | ||||||
|                 ; |  | ||||||
|  |  | ||||||
|             client = new UdpSession(); |  | ||||||
|             ((UdpSession)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((UdpSession)client) |  | ||||||
|         { |  | ||||||
|             Crc16CheckEnable = driverPropertys.Crc16CheckEnable, |  | ||||||
|             FrameTime = driverPropertys.FrameTime, |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             TimeOut = driverPropertys.TimeOut |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,243 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
|  |  | ||||||
| using SqlSugar; |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Modbus; |  | ||||||
| using ThingsGateway.Foundation.Extension; |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Modbus; |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusSerialServer : UpLoadBase |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private readonly ModbusSerialServerProperty driverPropertys = new(); |  | ||||||
|     private readonly ModbusSerialServerVariableProperty variablePropertys = new(); |  | ||||||
|     private Dictionary<ModbusAddress, DeviceVariableRunTime> _ModbusTags; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusSerialServer _plc; |  | ||||||
|     private ConcurrentQueue<(string, DeviceVariableRunTime)> Values = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusSerialServerDebugPage); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override UpDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _ModbusTags?.Values.ToList(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|     RpcSingletonService RpcCore { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         var list = Values.ToListWithDequeue(); |  | ||||||
|         foreach (var item in list) |  | ||||||
|         { |  | ||||||
|             if (cancellationToken.IsCancellationRequested) |  | ||||||
|                 break; |  | ||||||
|             var type = GetPropertyValue(item.Item2, nameof(ModbusSerialServerVariableProperty.ModbusType)); |  | ||||||
|             if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result)) |  | ||||||
|             { |  | ||||||
|                 await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, result, cancellationToken); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, item.Item2.DataTypeEnum, cancellationToken); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.SerialSession?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _ModbusTags?.Values?.ToList()?.ForEach(a => a.VariableValueChange -= VariableValueChange); |  | ||||||
|         if (_plc != null) |  | ||||||
|             _plc.WriteData -= WriteData; |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         _ModbusTags?.Clear(); |  | ||||||
|         _ModbusTags = null; |  | ||||||
|         Values?.Clear(); |  | ||||||
|         Values = null; |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         var service = new SerialSession(); |  | ||||||
|         FoundataionConfig.SetSerialProperty(new() |  | ||||||
|         { |  | ||||||
|             PortName = driverPropertys.PortName, |  | ||||||
|             BaudRate = driverPropertys.BaudRate, |  | ||||||
|             DataBits = driverPropertys.DataBits, |  | ||||||
|             Parity = driverPropertys.Parity, |  | ||||||
|             StopBits = driverPropertys.StopBits, |  | ||||||
|         }) |  | ||||||
|             ; |  | ||||||
|         service = new SerialSession(); |  | ||||||
|         ((SerialSession)service).Setup(FoundataionConfig); |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new(service) |  | ||||||
|         { |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             CacheTimeout = driverPropertys.CacheTimeout, |  | ||||||
|             MulStation = driverPropertys.MulStation |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         var _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|             .Where(b => !string.IsNullOrEmpty(GetPropertyValue(b, nameof(variablePropertys.ServiceAddress)))) |  | ||||||
|             .ToList(); |  | ||||||
|  |  | ||||||
|         tags.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange += VariableValueChange; |  | ||||||
|             VariableValueChange(a); |  | ||||||
|         }); |  | ||||||
|         _plc.WriteData += WriteData; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             _ModbusTags = tags.ToDictionary(a => |  | ||||||
|             { |  | ||||||
|                 ModbusAddress address = ModbusAddress.ParseFrom( |  | ||||||
|                     GetPropertyValue(a, nameof(variablePropertys.ServiceAddress)) |  | ||||||
|                     , driverPropertys.Station); |  | ||||||
|                 return address; |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|             tags.ForEach(a => |  | ||||||
|             { |  | ||||||
|                 a.VariableValueChange -= VariableValueChange; |  | ||||||
|             }); |  | ||||||
|             _plc.WriteData -= WriteData; |  | ||||||
|         } |  | ||||||
|         RpcCore = App.GetService<RpcSingletonService>(); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         var address = GetPropertyValue(collectVariableRunTime, nameof(variablePropertys.ServiceAddress)); |  | ||||||
|         if (address != null && collectVariableRunTime.Value != null) |  | ||||||
|         { |  | ||||||
|             Values?.Enqueue((address, collectVariableRunTime)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// RPC写入 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="address"></param> |  | ||||||
|     /// <param name="bytes"></param> |  | ||||||
|     /// <param name="thingsGatewayBitConverter"></param> |  | ||||||
|     /// <param name="client"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     private OperResult WriteData(ModbusAddress address, byte[] bytes, IThingsGatewayBitConverter thingsGatewayBitConverter, SerialSession client) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var tag = _ModbusTags.FirstOrDefault(a => a.Key?.AddressStart == address.AddressStart && a.Key?.Station == address.Station && a.Key?.ReadFunction == address.ReadFunction); |  | ||||||
|  |  | ||||||
|             if (tag.Value == null) return OperResult.CreateSuccessResult(); |  | ||||||
|             var enable = |  | ||||||
|                 GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBoolean() |  | ||||||
|                 && driverPropertys.DeviceRpcEnable; |  | ||||||
|             if (!enable) return new OperResult("不允许写入"); |  | ||||||
|             var type = GetPropertyValue(tag.Value, nameof(ModbusSerialServerVariableProperty.ModbusType)); |  | ||||||
|             var addressStr = GetPropertyValue(tag.Value, nameof(ModbusSerialServerVariableProperty.ServiceAddress)); |  | ||||||
|             if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result)) |  | ||||||
|             { |  | ||||||
|                 var resultTask1 = RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusSerialServer)}-{CurrentDevice.Name}", |  | ||||||
|                new Dictionary<string, string> |  | ||||||
| { |  | ||||||
|     { |  | ||||||
|                        tag.Value.Name, |  | ||||||
|                        thingsGatewayBitConverter.GetDataFormBytes(addressStr ,  bytes,result).ToString() |  | ||||||
|  |  | ||||||
|                    }, |  | ||||||
| } |  | ||||||
|  |  | ||||||
|                 ); |  | ||||||
|                 var result1 = resultTask1.ConfigureAwait(true).GetAwaiter().GetResult(); |  | ||||||
|                 return result1.FirstOrDefault().Value; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 var resultTask1 = RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusSerialServer)}-{CurrentDevice.Name}", |  | ||||||
|                new Dictionary<string, string> |  | ||||||
| { |  | ||||||
|     { |  | ||||||
|                        tag.Value.Name, |  | ||||||
|                        thingsGatewayBitConverter.GetDataFormBytes(addressStr ,   bytes,result).ToString() |  | ||||||
|                    }, |  | ||||||
| } |  | ||||||
|                 ); |  | ||||||
|                 var result1 = resultTask1.ConfigureAwait(true).GetAwaiter().GetResult(); |  | ||||||
|                 return result1.FirstOrDefault().Value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult(ex.Message); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,102 +0,0 @@ | |||||||
| #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.Plugin.Modbus; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusTcp : CollectBase |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp _plc; |  | ||||||
|  |  | ||||||
|     private readonly ModbusTcpProperty driverPropertys = new(); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusTcpDebugPage); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     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 cancellationToken) |  | ||||||
|     { |  | ||||||
|         await _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.TcpClient?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|     { |  | ||||||
|         if (client == null) |  | ||||||
|         { |  | ||||||
|             FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                 ; |  | ||||||
|             client = new TcpClient(); |  | ||||||
|             ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((TcpClient)client) |  | ||||||
|         { |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             FrameTime = driverPropertys.FrameTime, |  | ||||||
|             CacheTimeout = driverPropertys.CacheTimeout, |  | ||||||
|             ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             TimeOut = driverPropertys.TimeOut, |  | ||||||
|             IsCheckMessageId = driverPropertys.MessageIdCheckEnable |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,105 +0,0 @@ | |||||||
| #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.Plugin.Modbus; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusTcpDtu : CollectBase |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDtu _plc; |  | ||||||
|  |  | ||||||
|     private readonly ModbusTcpProperty driverPropertys = new(); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusTcpDebugPage); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     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 cancellationToken) |  | ||||||
|     { |  | ||||||
|         await _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.TcpService?.ServerState == ServerState.Running; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|     { |  | ||||||
|         if (client == null) |  | ||||||
|         { |  | ||||||
|             IPHost iPHost = new(driverPropertys.Port); |  | ||||||
|             if (!string.IsNullOrEmpty(driverPropertys.IP)) |  | ||||||
|             { |  | ||||||
|                 iPHost = new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"); |  | ||||||
|             } |  | ||||||
|             FoundataionConfig.SetListenIPHosts(new IPHost[] { iPHost }); |  | ||||||
|             client = new TcpService(); |  | ||||||
|             ((TcpService)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((TcpService)client) |  | ||||||
|         { |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             FrameTime = driverPropertys.FrameTime, |  | ||||||
|             CacheTimeout = driverPropertys.CacheTimeout, |  | ||||||
|             ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             TimeOut = driverPropertys.TimeOut, |  | ||||||
|             IsCheckMessageId = driverPropertys.MessageIdCheckEnable |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,239 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
|  |  | ||||||
| using SqlSugar; |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Modbus; |  | ||||||
| using ThingsGateway.Foundation.Extension; |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Modbus; |  | ||||||
| /// <summary> |  | ||||||
| /// <inheritdoc/> |  | ||||||
| /// </summary> |  | ||||||
| public class ModbusTcpServer : UpLoadBase |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private readonly ModbusTcpServerProperty driverPropertys = new(); |  | ||||||
|     private readonly ModbusTcpServerVariableProperty variablePropertys = new(); |  | ||||||
|     private Dictionary<ModbusAddress, DeviceVariableRunTime> _ModbusTags; |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpServer _plc; |  | ||||||
|     private ConcurrentQueue<(string, DeviceVariableRunTime)> Values = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusTcpServerDebugPage); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override UpDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _ModbusTags?.Values.ToList(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|     RpcSingletonService RpcCore { get; set; } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return _plc?.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         var list = Values.ToListWithDequeue(); |  | ||||||
|         foreach (var item in list) |  | ||||||
|         { |  | ||||||
|             if (cancellationToken.IsCancellationRequested) |  | ||||||
|                 break; |  | ||||||
|             var type = GetPropertyValue(item.Item2, nameof(ModbusTcpServerVariableProperty.ModbusType)); |  | ||||||
|             if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result)) |  | ||||||
|             { |  | ||||||
|                 await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, result, cancellationToken); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, item.Item2.DataTypeEnum, cancellationToken); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.TcpService?.ServerState == ServerState.Running; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _ModbusTags?.Values?.ToList()?.ForEach(a => a.VariableValueChange -= VariableValueChange); |  | ||||||
|         if (_plc != null) |  | ||||||
|             _plc.WriteData -= WriteData; |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         _ModbusTags?.Clear(); |  | ||||||
|         _ModbusTags = null; |  | ||||||
|         Values?.Clear(); |  | ||||||
|         Values = null; |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         IPHost iPHost = new(driverPropertys.Port); |  | ||||||
|         if (!string.IsNullOrEmpty(driverPropertys.IP)) |  | ||||||
|         { |  | ||||||
|             iPHost = new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}"); |  | ||||||
|         } |  | ||||||
|         FoundataionConfig.SetListenIPHosts(new IPHost[] { iPHost }); |  | ||||||
|         var service = new TcpService(); |  | ||||||
|         service.Setup(FoundataionConfig); |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new(service) |  | ||||||
|         { |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             CacheTimeout = driverPropertys.CacheTimeout, |  | ||||||
|             MulStation = driverPropertys.MulStation |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         var _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|             .Where(b => !string.IsNullOrEmpty(GetPropertyValue(b, nameof(variablePropertys.ServiceAddress)))) |  | ||||||
|             .ToList(); |  | ||||||
|  |  | ||||||
|         tags.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange += VariableValueChange; |  | ||||||
|             VariableValueChange(a); |  | ||||||
|         }); |  | ||||||
|         _plc.WriteData += WriteData; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             _ModbusTags = tags.ToDictionary(a => |  | ||||||
|             { |  | ||||||
|                 ModbusAddress address = ModbusAddress.ParseFrom( |  | ||||||
|                     GetPropertyValue(a, nameof(variablePropertys.ServiceAddress)) |  | ||||||
|                     , driverPropertys.Station); |  | ||||||
|                 return address; |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|             tags.ForEach(a => |  | ||||||
|             { |  | ||||||
|                 a.VariableValueChange -= VariableValueChange; |  | ||||||
|             }); |  | ||||||
|             _plc.WriteData -= WriteData; |  | ||||||
|         } |  | ||||||
|         RpcCore = App.GetService<RpcSingletonService>(); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         var address = GetPropertyValue(collectVariableRunTime, nameof(variablePropertys.ServiceAddress)); |  | ||||||
|         if (address != null && collectVariableRunTime.Value != null) |  | ||||||
|         { |  | ||||||
|             Values?.Enqueue((address, collectVariableRunTime)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// RPC写入 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="address"></param> |  | ||||||
|     /// <param name="bytes"></param> |  | ||||||
|     /// <param name="thingsGatewayBitConverter"></param> |  | ||||||
|     /// <param name="client"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     private OperResult WriteData(ModbusAddress address, byte[] bytes, IThingsGatewayBitConverter thingsGatewayBitConverter, SocketClient client) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var tag = _ModbusTags.FirstOrDefault(a => a.Key?.AddressStart == address.AddressStart && a.Key?.Station == address.Station && a.Key?.ReadFunction == address.ReadFunction); |  | ||||||
|  |  | ||||||
|             if (tag.Value == null) return OperResult.CreateSuccessResult(); |  | ||||||
|             var enable = |  | ||||||
|                 GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBoolean() |  | ||||||
|                 && driverPropertys.DeviceRpcEnable; |  | ||||||
|             if (!enable) return new OperResult("不允许写入"); |  | ||||||
|             var type = GetPropertyValue(tag.Value, nameof(ModbusTcpServerVariableProperty.ModbusType)); |  | ||||||
|             var addressStr = GetPropertyValue(tag.Value, nameof(ModbusTcpServerVariableProperty.ServiceAddress)); |  | ||||||
|             if (Enum.TryParse<DataTypeEnum>(type, out DataTypeEnum result)) |  | ||||||
|             { |  | ||||||
|                 var resultTask1 = RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{client.IP + ":" + client.Port}", |  | ||||||
|                new Dictionary<string, string> |  | ||||||
| { |  | ||||||
|     { |  | ||||||
|                        tag.Value.Name, |  | ||||||
|                        thingsGatewayBitConverter.GetDataFormBytes(addressStr ,  bytes,result).ToString() |  | ||||||
|  |  | ||||||
|                    }, |  | ||||||
| } |  | ||||||
|  |  | ||||||
|                 ); |  | ||||||
|                 var result1 = resultTask1.ConfigureAwait(true).GetAwaiter().GetResult(); |  | ||||||
|                 return result1.FirstOrDefault().Value; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 var resultTask1 = RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusTcpServer)}-{CurrentDevice.Name}-{client.IP + ":" + client.Port}", |  | ||||||
|                new Dictionary<string, string> |  | ||||||
| { |  | ||||||
|     { |  | ||||||
|                        tag.Value.Name, |  | ||||||
|                        thingsGatewayBitConverter.GetDataFormBytes(addressStr ,   bytes,result).ToString() |  | ||||||
|                    }, |  | ||||||
| } |  | ||||||
|                 ); |  | ||||||
|                 var result1 = resultTask1.ConfigureAwait(true).GetAwaiter().GetResult(); |  | ||||||
|                 return result1.FirstOrDefault().Value; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             return new OperResult(ex.Message); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,101 +0,0 @@ | |||||||
| #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.Plugin.Modbus; |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public class ModbusUdp : CollectBase |  | ||||||
| { |  | ||||||
|     private readonly ModbusUdpProperty driverPropertys = new(); |  | ||||||
|  |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp _plc; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => typeof(ModbusUdpDebugPage); |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsSupportRequest => true; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get => _plc?.ThingsGatewayBitConverter; } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override IReadWrite PLC => _plc; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         _plc.Disconnect(); |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return _plc.ConnectAsync(cancellationToken); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void InitDataAdapter() |  | ||||||
|     { |  | ||||||
|         _plc.SetDataAdapter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() |  | ||||||
|     { |  | ||||||
|         return _plc?.UdpSession?.CanSend == true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableSourceRead> LoadSourceRead(List<DeviceVariableRunTime> deviceVariables) |  | ||||||
|     { |  | ||||||
|         return _plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(deviceVariables, driverPropertys.MaxPack); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _plc?.Disconnect(); |  | ||||||
|         _plc?.SafeDispose(); |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|     { |  | ||||||
|         if (client == null) |  | ||||||
|         { |  | ||||||
|             FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                 .SetBindIPHost(new IPHost(0)) |  | ||||||
|                 ; |  | ||||||
|             client = new UdpSession(); |  | ||||||
|             ((UdpSession)client).Setup(FoundataionConfig); |  | ||||||
|         } |  | ||||||
|         //载入配置 |  | ||||||
|         _plc = new((UdpSession)client) |  | ||||||
|         { |  | ||||||
|             DataFormat = driverPropertys.DataFormat, |  | ||||||
|             FrameTime = driverPropertys.FrameTime, |  | ||||||
|             Station = driverPropertys.Station, |  | ||||||
|             TimeOut = driverPropertys.TimeOut, |  | ||||||
|             IsCheckMessageId = driverPropertys.MessageIdCheckEnable |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return await _plc.ReadAsync(address, length, cancellationToken); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,59 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/ModbusRtu" |  | ||||||
|  |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using Masa.Blazor; |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
|  |  | ||||||
| <SerialSessionPage @ref=SerialSessionPage></SerialSessionPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Station)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Station></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|             <MCheckbox Class="ma-1" Style="max-width:200px" Label=@(_plc.DescriptionWithOutSugar(x => x.Crc16CheckEnable)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Crc16CheckEnable></MCheckbox> |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
| } |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk.Razor"> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<Target Name="PostBuild" AfterTargets="PostBuildEvent"> |  | ||||||
|  |  | ||||||
| 		<Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25  md %25dir%25  
copy "$(TargetDir)*Modbus*.dll"  %25dir%25


" /> |  | ||||||
|  |  | ||||||
| 	</Target> |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIBase.cs" Link="DebugPage\DriverDebugUIBase.cs" /> |  | ||||||
| 		<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor.cs" Link="DebugPage\DriverDebugUIPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor.cs" Link="DebugPage\SerialSessionPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor.cs" Link="DebugPage\TcpClientPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor.cs" Link="DebugPage\TcpServerPage.razor.cs" /> |  | ||||||
| 		<Compile Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor.cs" Link="DebugPage\UdpSessionPage.razor.cs" /> |  | ||||||
| 		<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\DriverDebugUIPage.razor" Link="DebugPage\DriverDebugUIPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\SerialSessionPage.razor" Link="DebugPage\SerialSessionPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpClientPage.razor" Link="DebugPage\TcpClientPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\TcpServerPage.razor" Link="DebugPage\TcpServerPage.razor" /> |  | ||||||
| 		<Content Include="..\..\Demo\ThingsGateway.Foundation.Demo.Rcl\Components\DebugPage\UdpSessionPage.razor" Link="DebugPage\UdpSessionPage.razor" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj"> |  | ||||||
| 			<Private>false</Private> |  | ||||||
| 			<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies> |  | ||||||
| 			<ExcludeAssets>runtime</ExcludeAssets> |  | ||||||
| 		</ProjectReference> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @using System.Net.Http |  | ||||||
| @using Microsoft.AspNetCore.Components.Forms |  | ||||||
| @using Microsoft.AspNetCore.Components.Routing |  | ||||||
| @using Microsoft.AspNetCore.Components.Web |  | ||||||
| @using Microsoft.AspNetCore.Components.Web.Virtualization |  | ||||||
| @using Microsoft.JSInterop |  | ||||||
| @using BlazorComponent |  | ||||||
| @using Masa.Blazor |  | ||||||
| @using Masa.Blazor.Presets |  | ||||||
| @using System.Net.Http.Json |  | ||||||
| @using System.IO; |  | ||||||
| @using System.Text.Json; |  | ||||||
| @using System.Reflection; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Components; |  | ||||||
| @using ThingsGateway.Admin.Core; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension.String; |  | ||||||
| @using ThingsGateway.Admin.Application; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Core; |  | ||||||
| @using ThingsGateway.Gateway.Application; |  | ||||||
| @using ThingsGateway.Gateway.Core; |  | ||||||
| @@ -1,601 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| using IoTSharp.Data; |  | ||||||
|  |  | ||||||
| using Mapster; |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
|  |  | ||||||
| using MQTTnet; |  | ||||||
| using MQTTnet.Client; |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Admin.Core; |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Mqtt; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// 参考IotSharpClient.SDK.MQTT |  | ||||||
| /// </summary> |  | ||||||
| public class IotSharpClient : UpLoadBase |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// rpcmethodname存疑,定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write" |  | ||||||
|     /// </summary> |  | ||||||
|     private const string WriteMethod = "WRITE"; |  | ||||||
|  |  | ||||||
|     private readonly IotSharpClientProperty driverPropertys = new(); |  | ||||||
|     private readonly EasyLock easyLock = new(); |  | ||||||
|     private readonly IotSharpClientVariableProperty variablePropertys = new(); |  | ||||||
|     private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new(); |  | ||||||
|     private ConcurrentQueue<VariableData> _collectVariableRunTimes = new(); |  | ||||||
|     private GlobalDeviceData _globalDeviceData; |  | ||||||
|  |  | ||||||
|     private IMqttClient _mqttClient; |  | ||||||
|  |  | ||||||
|     private MqttClientOptions _mqttClientOptions; |  | ||||||
|  |  | ||||||
|     private MqttClientSubscribeOptions _mqttSubscribeOptions; |  | ||||||
|  |  | ||||||
|     private RpcSingletonService _rpcCore; |  | ||||||
|     private List<DeviceVariableRunTime> _uploadVariables = new(); |  | ||||||
|     private CollectDeviceWorker collectDeviceHostService; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => null; |  | ||||||
|     private TimerTick exVariableTimerTick; |  | ||||||
|     private TimerTick exDeviceTimerTick; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override UpDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         if (_mqttClient != null) |  | ||||||
|         { |  | ||||||
|             var result = await TryMqttClientAsync(cancellationToken); |  | ||||||
|             if (!result.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 LogMessage?.LogWarning($"{ToString()}-连接MqttServer失败:{result.Message}"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var varList = _collectVariableRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (varList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                     var varData = varList.GroupBy(a => a.DeviceName).ToList(); |  | ||||||
|                     foreach (var item in varData) |  | ||||||
|                     { |  | ||||||
|                         try |  | ||||||
|                         { |  | ||||||
|                             Dictionary<string, object> nameValueDict = new(); |  | ||||||
|                             foreach (var pair in item) |  | ||||||
|                             { |  | ||||||
|                                 //只用最新的变量值 |  | ||||||
|                                 nameValueDict.AddOrUpdate(pair.Name, pair.Value); |  | ||||||
|                             } |  | ||||||
|                             if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                             { |  | ||||||
|                                 await MqttUp($"devices/{item.Key}/telemetry", nameValueDict.ToJsonString(), cancellationToken); |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                         catch (Exception ex) |  | ||||||
|                         { |  | ||||||
|                             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exVariableTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         var varList = _uploadVariables.Adapt<List<VariableData>>(); |  | ||||||
|                         if (varList?.Count != 0) |  | ||||||
|                         { |  | ||||||
|                             //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                             var varData = varList.GroupBy(a => a.DeviceName).ToList(); |  | ||||||
|                             foreach (var item in varData) |  | ||||||
|                             { |  | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     Dictionary<string, object> nameValueDict = new(); |  | ||||||
|                                     foreach (var pair in item) |  | ||||||
|                                     { |  | ||||||
|                                         //只用最新的变量值 |  | ||||||
|                                         nameValueDict.AddOrUpdate(pair.Name, pair.Value); |  | ||||||
|                                     } |  | ||||||
|                                     if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                     { |  | ||||||
|                                         await MqttUp($"devices/{item.Key}/telemetry", nameValueDict.ToJsonString(), cancellationToken); |  | ||||||
|                                     } |  | ||||||
|                                     else |  | ||||||
|                                     { |  | ||||||
|                                         break; |  | ||||||
|                                     } |  | ||||||
|  |  | ||||||
|                                 } |  | ||||||
|                                 catch (Exception ex) |  | ||||||
|                                 { |  | ||||||
|                                     LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var devList = _collectDeviceRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (devList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                     var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                     foreach (var item in devData) |  | ||||||
|                     { |  | ||||||
|                         try |  | ||||||
|                         { |  | ||||||
|                             if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                             { |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         catch (Exception ex) |  | ||||||
|                         { |  | ||||||
|                             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exDeviceTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     var devList = _collectDevice.Adapt<List<DeviceData>>(); |  | ||||||
|                     if (devList?.Count != 0) |  | ||||||
|                     { |  | ||||||
|                         //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                         var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                         foreach (var item in devData) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                 { |  | ||||||
|  |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() => _mqttClient?.IsConnected == true; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string ToString() |  | ||||||
|     { |  | ||||||
|         return $" {nameof(IotSharpClient)}-IP:{driverPropertys.IP}-Port:{driverPropertys.Port}-Accesstoken:{driverPropertys.Accesstoken}"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             _globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange); |  | ||||||
|  |  | ||||||
|             _collectDevice?.ForEach(a => |  | ||||||
|             { |  | ||||||
|                 a.DeviceStatusChange -= DeviceStatusChange; |  | ||||||
|             }); |  | ||||||
|             _mqttClient?.SafeDispose(); |  | ||||||
|             _mqttClient = null; |  | ||||||
|             _uploadVariables = null; |  | ||||||
|             _collectDeviceRunTimes.Clear(); |  | ||||||
|             _collectVariableRunTimes.Clear(); |  | ||||||
|             _collectDeviceRunTimes = null; |  | ||||||
|             _collectVariableRunTimes = null; |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogError(ex, ToString()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     private List<CollectDeviceRunTime> _collectDevice; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         var mqttFactory = new MqttFactory(new PrivateLogger(LogMessage)); |  | ||||||
|         _mqttClientOptions = mqttFactory.CreateClientOptionsBuilder() |  | ||||||
|            .WithClientId(Guid.NewGuid().ToString()) |  | ||||||
|            .WithCredentials(driverPropertys.Accesstoken)//账密 |  | ||||||
|            .WithTcpServer(driverPropertys.IP, driverPropertys.Port)//服务器 |  | ||||||
|            .WithCleanSession(true) |  | ||||||
|            .WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0)) |  | ||||||
|            .Build(); |  | ||||||
|         _mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder() |  | ||||||
|             .WithTopicFilter( |  | ||||||
|                 f => |  | ||||||
|                 { |  | ||||||
|                     f.WithTopic($"devices/+/rpc/request/+/+");//RPC控制请求,需要订阅 |  | ||||||
|                 }) |  | ||||||
|  |  | ||||||
|             .Build(); |  | ||||||
|         _mqttClient = mqttFactory.CreateMqttClient(); |  | ||||||
|         _mqttClient.ConnectedAsync += MqttClient_ConnectedAsync; |  | ||||||
|         _mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync; |  | ||||||
|         _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|         _rpcCore = App.GetService<RpcSingletonService>(); |  | ||||||
|         collectDeviceHostService = BackgroundServiceUtil.GetBackgroundService<CollectDeviceWorker>(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|            .Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue()) |  | ||||||
|            .ToList(); |  | ||||||
|  |  | ||||||
|         _uploadVariables = tags; |  | ||||||
|  |  | ||||||
|         _collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList(); |  | ||||||
|  |  | ||||||
|         _collectDevice?.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange += DeviceStatusChange; |  | ||||||
|         }); |  | ||||||
|         _uploadVariables.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange += VariableValueChange; |  | ||||||
|         }); |  | ||||||
|         if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000; |  | ||||||
|         exVariableTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|         exDeviceTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/rpc/request/")) |  | ||||||
|         { |  | ||||||
|             var tps = e.ApplicationMessage.Topic.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); |  | ||||||
|             var rpcmethodname = tps[4]; |  | ||||||
|             var rpcdevicename = tps[1]; |  | ||||||
|             var rpcrequestid = tps[5]; |  | ||||||
|             if (!string.IsNullOrEmpty(rpcmethodname) && !string.IsNullOrEmpty(rpcdevicename) && !string.IsNullOrEmpty(rpcrequestid)) |  | ||||||
|             { |  | ||||||
|                 var rpcResponse = new RpcResponse() |  | ||||||
|                 { |  | ||||||
|                     DeviceId = rpcdevicename, |  | ||||||
|                     ResponseId = rpcrequestid, |  | ||||||
|                     Method = rpcmethodname, |  | ||||||
|                     Success = false, |  | ||||||
|                     Data = "参数为空" |  | ||||||
|                 }; |  | ||||||
|                 await SendResponseAsync(rpcResponse); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (!driverPropertys.DeviceRpcEnable) |  | ||||||
|             { |  | ||||||
|                 var rpcResponse = new RpcResponse() |  | ||||||
|                 { |  | ||||||
|                     DeviceId = rpcdevicename, |  | ||||||
|                     ResponseId = rpcrequestid, |  | ||||||
|                     Method = rpcmethodname, |  | ||||||
|                     Success = false, |  | ||||||
|                     Data = "不允许写入" |  | ||||||
|                 }; |  | ||||||
|                 await SendResponseAsync(rpcResponse); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             //rpcmethodname定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write" |  | ||||||
|             if (rpcmethodname.ToUpper() != WriteMethod) |  | ||||||
|             { |  | ||||||
|                 var rpcResponse = new RpcResponse() |  | ||||||
|                 { |  | ||||||
|                     DeviceId = rpcdevicename, |  | ||||||
|                     ResponseId = rpcrequestid, |  | ||||||
|                     Method = rpcmethodname, |  | ||||||
|                     Success = false, |  | ||||||
|                     Data = "不支持的方法" |  | ||||||
|                 }; |  | ||||||
|                 await SendResponseAsync(rpcResponse); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 RpcResponse rpcResponse = new(); |  | ||||||
|                 var nameValue = e.ApplicationMessage.ConvertPayloadToString().FromJsonString<List<KeyValuePair<string, string>>>(); |  | ||||||
|                 Dictionary<string, OperResult> results = new(); |  | ||||||
|                 if (nameValue?.Count > 0) |  | ||||||
|                 { |  | ||||||
|                     foreach (var item in nameValue) |  | ||||||
|                     { |  | ||||||
|                         var tag = _uploadVariables.FirstOrDefault(a => a.Name == item.Key); |  | ||||||
|                         if (tag != null) |  | ||||||
|                         { |  | ||||||
|                             var rpcEnable = |  | ||||||
| GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean() |  | ||||||
| && driverPropertys.DeviceRpcEnable; |  | ||||||
|                             if (rpcEnable == true) |  | ||||||
|                             { |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 results.Add(item.Key, new OperResult("权限不足,变量不支持写入")); |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             results.Add(item.Key, new OperResult("不存在该变量")); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + rpcrequestid, nameValue |  | ||||||
|                         .Where(a => !results.Any(b => b.Key == a.Key)) |  | ||||||
|                         .ToDictionary(a => a.Key, a => a.Value)); |  | ||||||
|  |  | ||||||
|                     results.AddRange(result); |  | ||||||
|                     rpcResponse = new() |  | ||||||
|                     { |  | ||||||
|                         DeviceId = rpcdevicename, |  | ||||||
|                         ResponseId = rpcrequestid, |  | ||||||
|                         Method = rpcmethodname, |  | ||||||
|                         Success = !results.Any(a => !a.Value.IsSuccess), |  | ||||||
|                         Data = results.ToJsonString() |  | ||||||
|                     }; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     rpcResponse = new() |  | ||||||
|                     { |  | ||||||
|                         DeviceId = rpcdevicename, |  | ||||||
|                         ResponseId = rpcrequestid, |  | ||||||
|                         Method = rpcmethodname, |  | ||||||
|                         Success = false, |  | ||||||
|                         Data = "消息体参数无法解析" |  | ||||||
|                     }; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 await SendResponseAsync(rpcResponse); |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async Task SendResponseAsync(RpcResponse rpcResponse) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 var topic = $"devices/{rpcResponse.DeviceId}/rpc/response/{rpcResponse.Method}/{rpcResponse.ResponseId}"; |  | ||||||
|  |  | ||||||
|                 var variableMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic($"{topic}") |  | ||||||
| .WithPayload(rpcResponse.ToJsonString()).Build(); |  | ||||||
|                 var isConnect = await TryMqttClientAsync(CancellationToken.None); |  | ||||||
|                 if (isConnect.IsSuccess) |  | ||||||
|                     await _mqttClient.PublishAsync(variableMessage); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg) |  | ||||||
|     { |  | ||||||
|         var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions); |  | ||||||
|  |  | ||||||
|         if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10)) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(subResult.Items |  | ||||||
|                 .Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10) |  | ||||||
|                 .Select(a => a.ToString()).ToJsonString()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// 上传mqtt内容,并进行离线缓存 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="topic"></param> |  | ||||||
|     /// <param name="payLoad"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     private async Task MqttUp(string topic, string payLoad, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         var variableMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic(topic) |  | ||||||
| .WithPayload(payLoad).Build(); |  | ||||||
|         var isConnect = await TryMqttClientAsync(cancellationToken); |  | ||||||
|         if (isConnect.IsSuccess) |  | ||||||
|         { |  | ||||||
|             //连接成功时补发缓存数据 |  | ||||||
|             var cacheData = await CacheDb.GetCacheData(); |  | ||||||
|             foreach (var item in cacheData) |  | ||||||
|             { |  | ||||||
|                 var cacheMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic(item.Topic) |  | ||||||
| .WithPayload(item.CacheStr).Build(); |  | ||||||
|                 var cacheResult = await _mqttClient.PublishAsync(cacheMessage, cancellationToken); |  | ||||||
|                 if (cacheResult.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     await CacheDb.DeleteCacheData(item.Id); |  | ||||||
|                     LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}"); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var result = await _mqttClient.PublishAsync(variableMessage, cancellationToken); |  | ||||||
|             if (!result.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{topic}{Environment.NewLine}负载:{payLoad}"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task<OperResult> TryMqttClientAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         if (_mqttClient?.IsConnected == true) |  | ||||||
|             return OperResult.CreateSuccessResult(); |  | ||||||
|         return await Cilent(); |  | ||||||
|  |  | ||||||
|         async Task<OperResult> Cilent() |  | ||||||
|         { |  | ||||||
|             if (_mqttClient?.IsConnected == true) |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await easyLock.WaitAsync(); |  | ||||||
|                 if (_mqttClient?.IsConnected == true) |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 using var timeoutToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(driverPropertys.ConnectTimeOut)); |  | ||||||
|                 using CancellationTokenSource StoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token); |  | ||||||
|                 if (_mqttClient?.IsConnected == true) |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 if (_mqttClient == null) |  | ||||||
|                     return new OperResult("未初始化"); |  | ||||||
|                 var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, StoppingToken.Token); |  | ||||||
|                 if (result.ResultCode == MqttClientConnectResultCode.Success) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result.ReasonString); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 return new OperResult(ex); |  | ||||||
|             } |  | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 easyLock.Release(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,569 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| using Mapster; |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
|  |  | ||||||
| using MQTTnet; |  | ||||||
| using MQTTnet.Client; |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Text; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Mqtt; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// MqttClient |  | ||||||
| /// </summary> |  | ||||||
| public class MqttClient : UpLoadBase |  | ||||||
| { |  | ||||||
|     private readonly MqttClientProperty driverPropertys = new(); |  | ||||||
|     private readonly EasyLock easyLock = new(); |  | ||||||
|     private readonly MqttClientVariableProperty variablePropertys = new(); |  | ||||||
|     private List<CollectDeviceRunTime> _collectDevice; |  | ||||||
|     private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new(); |  | ||||||
|     private ConcurrentQueue<VariableData> _collectVariableRunTimes = new(); |  | ||||||
|     private GlobalDeviceData _globalDeviceData; |  | ||||||
|     private IMqttClient _mqttClient; |  | ||||||
|  |  | ||||||
|     private MqttClientOptions _mqttClientOptions; |  | ||||||
|  |  | ||||||
|     private MqttClientSubscribeOptions _mqttSubscribeOptions; |  | ||||||
|  |  | ||||||
|     private RpcSingletonService _rpcCore; |  | ||||||
|  |  | ||||||
|     private List<DeviceVariableRunTime> _uploadVariables = new(); |  | ||||||
|  |  | ||||||
|     private CollectDeviceWorker collectDeviceHostService; |  | ||||||
|     private TimerTick exDeviceTimerTick; |  | ||||||
|  |  | ||||||
|     private TimerTick exVariableTimerTick; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => null; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override UpDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         if (_mqttClient != null) |  | ||||||
|         { |  | ||||||
|             var result = await TryMqttClientAsync(cancellationToken); |  | ||||||
|             if (!result.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 LogMessage?.LogWarning($"{ToString()}-连接MqttServer失败:{result.Message}"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var varList = _collectVariableRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (varList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                     var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                     foreach (var item in varData) |  | ||||||
|                     { |  | ||||||
|                         try |  | ||||||
|                         { |  | ||||||
|                             if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                             { |  | ||||||
|                                 await MqttUp($"{driverPropertys.VariableTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel), cancellationToken); |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                         catch (Exception ex) |  | ||||||
|                         { |  | ||||||
|                             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exVariableTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         var varList = _uploadVariables.Adapt<List<VariableData>>(); |  | ||||||
|                         if (varList?.Count != 0) |  | ||||||
|                         { |  | ||||||
|                             //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                             var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                             foreach (var item in varData) |  | ||||||
|                             { |  | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                     { |  | ||||||
|  |  | ||||||
|                                         await MqttUp($"{driverPropertys.VariableTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel), cancellationToken); |  | ||||||
|  |  | ||||||
|                                     } |  | ||||||
|                                     else |  | ||||||
|                                     { |  | ||||||
|                                         break; |  | ||||||
|                                     } |  | ||||||
|  |  | ||||||
|                                 } |  | ||||||
|                                 catch (Exception ex) |  | ||||||
|                                 { |  | ||||||
|                                     LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var devList = _collectDeviceRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (devList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                     var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                     foreach (var item in devData) |  | ||||||
|                     { |  | ||||||
|                         try |  | ||||||
|                         { |  | ||||||
|                             if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                             { |  | ||||||
|                                 await MqttUp($"{driverPropertys.DeviceTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel), cancellationToken); |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         catch (Exception ex) |  | ||||||
|                         { |  | ||||||
|                             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exDeviceTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     var devList = _collectDevice.Adapt<List<DeviceData>>(); |  | ||||||
|                     if (devList?.Count != 0) |  | ||||||
|                     { |  | ||||||
|                         //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                         var devData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                         foreach (var item in devData) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                 { |  | ||||||
|                                     await MqttUp($"{driverPropertys.DeviceTopic}", item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel), cancellationToken); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override bool IsConnected() => _mqttClient?.IsConnected == true; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string ToString() |  | ||||||
|     { |  | ||||||
|         return $" {nameof(MqttClient)} IP:{driverPropertys.IP} Port:{driverPropertys.Port}"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             _globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange); |  | ||||||
|  |  | ||||||
|             _globalDeviceData?.CollectDevices?.ForEach(a => |  | ||||||
|             { |  | ||||||
|                 a.DeviceStatusChange -= DeviceStatusChange; |  | ||||||
|             }); |  | ||||||
|             _mqttClient?.SafeDispose(); |  | ||||||
|             _mqttClient = null; |  | ||||||
|             _uploadVariables = null; |  | ||||||
|             _collectDeviceRunTimes.Clear(); |  | ||||||
|             _collectVariableRunTimes.Clear(); |  | ||||||
|             _collectDeviceRunTimes = null; |  | ||||||
|             _collectVariableRunTimes = null; |  | ||||||
|             base.Dispose(disposing); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogError(ex, ToString()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         var mqttFactory = new MqttFactory(new PrivateLogger(LogMessage)); |  | ||||||
|         _mqttClientOptions = mqttFactory.CreateClientOptionsBuilder() |  | ||||||
|            .WithClientId(driverPropertys.ConnectId) |  | ||||||
|            .WithCredentials(driverPropertys.UserName, driverPropertys.Password)//账密 |  | ||||||
|            .WithTcpServer(driverPropertys.IP, driverPropertys.Port)//服务器 |  | ||||||
|            .WithCleanSession(true) |  | ||||||
|            .WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0)) |  | ||||||
|            .WithoutThrowOnNonSuccessfulConnectResponse() |  | ||||||
|            .Build(); |  | ||||||
|         _mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder() |  | ||||||
|             .WithTopicFilter( |  | ||||||
|                 f => |  | ||||||
|                 { |  | ||||||
|                     f.WithTopic(driverPropertys.RpcWriteTopic); |  | ||||||
|                 }) |  | ||||||
|                      .WithTopicFilter( |  | ||||||
|                 f => |  | ||||||
|                 { |  | ||||||
|                     f.WithTopic(driverPropertys.QuestRpcTopic); |  | ||||||
|                 }) |  | ||||||
|             .Build(); |  | ||||||
|         _mqttClient = mqttFactory.CreateMqttClient(); |  | ||||||
|         _mqttClient.ConnectedAsync += MqttClient_ConnectedAsync; |  | ||||||
|         _mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync; |  | ||||||
|         _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|         _rpcCore = App.GetService<RpcSingletonService>(); |  | ||||||
|         collectDeviceHostService = BackgroundServiceUtil.GetBackgroundService<CollectDeviceWorker>(); |  | ||||||
|  |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|            .Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue()) |  | ||||||
|            .ToList(); |  | ||||||
|  |  | ||||||
|         _uploadVariables = tags; |  | ||||||
|  |  | ||||||
|         _collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList(); |  | ||||||
|         if (!driverPropertys.IsInterval) |  | ||||||
|         { |  | ||||||
|             _collectDevice.ForEach(a => |  | ||||||
|             { |  | ||||||
|                 a.DeviceStatusChange += DeviceStatusChange; |  | ||||||
|             }); |  | ||||||
|             _uploadVariables.ForEach(a => |  | ||||||
|             { |  | ||||||
|                 a.VariableValueChange += VariableValueChange; |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000; |  | ||||||
|         exVariableTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|         exDeviceTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task AllPublishAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         //保留消息 |  | ||||||
|         //分解List,避免超出mqtt字节大小限制 |  | ||||||
|         var varData = _globalDeviceData.AllVariables.Adapt<List<VariableData>>().ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|         var devData = _globalDeviceData.AllVariables.Adapt<List<DeviceData>>().ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|         var isConnect = await TryMqttClientAsync(cancellationToken); |  | ||||||
|         foreach (var item in devData) |  | ||||||
|         { |  | ||||||
|             var devMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic($"{driverPropertys.DeviceTopic}") |  | ||||||
| .WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel)).Build(); |  | ||||||
|             if (isConnect.IsSuccess) |  | ||||||
|                 await _mqttClient.PublishAsync(devMessage, cancellationToken); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         foreach (var item in varData) |  | ||||||
|         { |  | ||||||
|             var varMessage = new MqttApplicationMessageBuilder() |  | ||||||
|             .WithTopic($"{driverPropertys.VariableTopic}") |  | ||||||
|             .WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel)).Build(); |  | ||||||
|             if (isConnect.IsSuccess) |  | ||||||
|                 await _mqttClient.PublishAsync(varMessage, cancellationToken); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs args) |  | ||||||
|     { |  | ||||||
|         if (args.ApplicationMessage.Topic == driverPropertys.QuestRpcTopic && args.ApplicationMessage.PayloadSegment.Count > 0) |  | ||||||
|         { |  | ||||||
|             await AllPublishAsync(CancellationToken.None); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (!driverPropertys.DeviceRpcEnable || string.IsNullOrEmpty(args.ClientId)) |  | ||||||
|             return; |  | ||||||
|         if (args.ApplicationMessage.Topic != driverPropertys.RpcWriteTopic) |  | ||||||
|             return; |  | ||||||
|         var rpcDatas = Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment).FromJsonString<MqttRpcNameVaueWithId>(); |  | ||||||
|         if (rpcDatas == null) |  | ||||||
|             return; |  | ||||||
|  |  | ||||||
|         MqttRpcResult mqttRpcResult = new() { RpcId = rpcDatas.RpcId, Success = true }; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             foreach (var rpcData in rpcDatas.WriteInfos) |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|                 var tag = _uploadVariables.FirstOrDefault(a => a.Name == rpcData.Key); |  | ||||||
|                 if (tag != null) |  | ||||||
|                 { |  | ||||||
|                     var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean(); |  | ||||||
|                     if (rpcEnable == true) |  | ||||||
|                     { |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         mqttRpcResult.Success = false; |  | ||||||
|                         mqttRpcResult.Message.Add(rpcData.Key, new("权限不足,变量不支持写入")); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     mqttRpcResult.Success = false; |  | ||||||
|                     mqttRpcResult.Message.Add(rpcData.Key, new("不存在该变量")); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + args.ClientId, |  | ||||||
|                 rpcDatas.WriteInfos.Where( |  | ||||||
|                 a => !mqttRpcResult.Message.Any(b => b.Key == a.Key)).ToDictionary(a => a.Key, a => a.Value)); |  | ||||||
|  |  | ||||||
|             mqttRpcResult.Message.AddRange(result); |  | ||||||
|             mqttRpcResult.Success = !mqttRpcResult.Message.Any(a => !a.Value.IsSuccess); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var variableMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic($"{driverPropertys.RpcSubTopic}") |  | ||||||
| .WithPayload(mqttRpcResult.ToJsonString()).Build(); |  | ||||||
|             var isConnect = await TryMqttClientAsync(CancellationToken.None); |  | ||||||
|             if (isConnect.IsSuccess) |  | ||||||
|                 await _mqttClient.PublishAsync(variableMessage); |  | ||||||
|         } |  | ||||||
|         catch |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg) |  | ||||||
|     { |  | ||||||
|         var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions); |  | ||||||
|         if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10)) |  | ||||||
|         { |  | ||||||
|             LogMessage?.Warning($"订阅失败-{subResult.Items |  | ||||||
|                 .Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10) |  | ||||||
|                 .Select(a => |  | ||||||
|                 new |  | ||||||
|                 { |  | ||||||
|                     Topic = a.TopicFilter.Topic, |  | ||||||
|                     ResultCode = a.ResultCode.ToString() |  | ||||||
|                 } |  | ||||||
|                 ) |  | ||||||
|                 .ToJsonString()}"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     /// <summary> |  | ||||||
|     /// 上传mqtt内容,并进行离线缓存 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="topic"></param> |  | ||||||
|     /// <param name="payLoad"></param> |  | ||||||
|     /// <param name="cancellationToken"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     private async Task MqttUp(string topic, string payLoad, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         var variableMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic(topic) |  | ||||||
| .WithPayload(payLoad).Build(); |  | ||||||
|         var isConnect = await TryMqttClientAsync(cancellationToken); |  | ||||||
|         if (isConnect.IsSuccess) |  | ||||||
|         { |  | ||||||
|             //连接成功时补发缓存数据 |  | ||||||
|             var cacheData = await CacheDb.GetCacheData(); |  | ||||||
|             foreach (var item in cacheData) |  | ||||||
|             { |  | ||||||
|                 var cacheMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic(item.Topic) |  | ||||||
| .WithPayload(item.CacheStr).Build(); |  | ||||||
|                 var cacheResult = await _mqttClient.PublishAsync(cacheMessage, cancellationToken); |  | ||||||
|                 if (cacheResult.IsSuccess) |  | ||||||
|                 { |  | ||||||
|                     await CacheDb.DeleteCacheData(item.Id); |  | ||||||
|                     LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}"); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var result = await _mqttClient.PublishAsync(variableMessage, cancellationToken); |  | ||||||
|             if (!result.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{topic}{Environment.NewLine}负载:{payLoad}"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             await CacheDb.AddCacheData(topic, payLoad, driverPropertys.CacheMaxCount); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     private async Task<OperResult> TryMqttClientAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         if (_mqttClient?.IsConnected == true) |  | ||||||
|             return OperResult.CreateSuccessResult(); |  | ||||||
|         return await Cilent(); |  | ||||||
|  |  | ||||||
|         async Task<OperResult> Cilent() |  | ||||||
|         { |  | ||||||
|             if (_mqttClient?.IsConnected == true) |  | ||||||
|                 return OperResult.CreateSuccessResult(); |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await easyLock.WaitAsync(); |  | ||||||
|                 if (_mqttClient?.IsConnected == true) |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 using var timeoutToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(driverPropertys.ConnectTimeOut)); |  | ||||||
|                 using CancellationTokenSource StoppingToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token); |  | ||||||
|                 if (_mqttClient?.IsConnected == true) |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 if (_mqttClient == null) |  | ||||||
|                 { |  | ||||||
|                     return new OperResult("未初始化"); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, StoppingToken.Token); |  | ||||||
|                 if (result.ResultCode == MqttClientConnectResultCode.Success) |  | ||||||
|                 { |  | ||||||
|                     return OperResult.CreateSuccessResult(); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return new OperResult(result.ReasonString); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 return new OperResult(ex); |  | ||||||
|             } |  | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 easyLock.Release(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,364 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| using Mapster; |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
|  |  | ||||||
| using MQTTnet; |  | ||||||
| using MQTTnet.Internal; |  | ||||||
| using MQTTnet.Protocol; |  | ||||||
| using MQTTnet.Server; |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Net; |  | ||||||
| using System.Text; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Admin.Application; |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Mqtt; |  | ||||||
| /// <summary> |  | ||||||
| /// MqttServer |  | ||||||
| /// </summary> |  | ||||||
| public class MqttServer : UpLoadBase |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private readonly MqttServerProperty driverPropertys = new(); |  | ||||||
|     private readonly MqttClientVariableProperty variablePropertys = new(); |  | ||||||
|     private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new(); |  | ||||||
|     private ConcurrentQueue<VariableData> _collectVariableRunTimes = new(); |  | ||||||
|     private GlobalDeviceData _globalDeviceData; |  | ||||||
|  |  | ||||||
|     private MQTTnet.Server.MqttServer _mqttServer; |  | ||||||
|     private RpcSingletonService _rpcCore; |  | ||||||
|     private List<DeviceVariableRunTime> _uploadVariables = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => null; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override UpDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         if (_mqttServer != null) |  | ||||||
|         { |  | ||||||
|             _mqttServer.ValidatingConnectionAsync += MqttServer_ValidatingConnectionAsync; |  | ||||||
|             _mqttServer.InterceptingPublishAsync += MqttServer_InterceptingPublishAsync; |  | ||||||
|             _mqttServer.LoadingRetainedMessageAsync += MqttServer_LoadingRetainedMessageAsync; |  | ||||||
|             _mqttServer.InterceptingSubscriptionAsync += MqttServer_InterceptingSubscriptionAsync; ; |  | ||||||
|             await _mqttServer.StartAsync(); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             ////变化推送 |  | ||||||
|             var varList = _collectVariableRunTimes.ToListWithDequeue(); |  | ||||||
|  |  | ||||||
|             if (varList?.Count != 0) |  | ||||||
|             { |  | ||||||
|                 //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                 var varData = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                 foreach (var item in varData) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                         { |  | ||||||
|                             var message = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic($"{driverPropertys.VariableTopic}") |  | ||||||
| .WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel)).Build(); |  | ||||||
|                             await _mqttServer.InjectApplicationMessage( |  | ||||||
|                                     new InjectedMqttApplicationMessage(message), cancellationToken); |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             break; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             ////变化推送 |  | ||||||
|             var devList = _collectDeviceRunTimes.ToListWithDequeue(); |  | ||||||
|             if (devList?.Count != 0) |  | ||||||
|             { |  | ||||||
|                 //分解List,避免超出mqtt字节大小限制 |  | ||||||
|                 var varData = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                 foreach (var item in varData) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                         { |  | ||||||
|                             var message = new MqttApplicationMessageBuilder() |  | ||||||
|                         .WithTopic($"{driverPropertys.DeviceTopic}") |  | ||||||
|                         .WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel)).Build(); |  | ||||||
|                             await _mqttServer.InjectApplicationMessage( |  | ||||||
|                                     new InjectedMqttApplicationMessage(message), cancellationToken); |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             break; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() => _mqttServer?.IsStarted == true; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override string ToString() |  | ||||||
|     { |  | ||||||
|         return $" {nameof(MqttServer)} IP:{driverPropertys.IP} Port:{driverPropertys.Port}"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         if (_mqttServer != null) |  | ||||||
|         { |  | ||||||
|             _mqttServer.ValidatingConnectionAsync -= MqttServer_ValidatingConnectionAsync; |  | ||||||
|             _mqttServer.InterceptingPublishAsync -= MqttServer_InterceptingPublishAsync; |  | ||||||
|             _mqttServer.LoadingRetainedMessageAsync -= MqttServer_LoadingRetainedMessageAsync; |  | ||||||
|             _mqttServer.InterceptingSubscriptionAsync -= MqttServer_InterceptingSubscriptionAsync; ; |  | ||||||
|             _mqttServer?.SafeDispose(); |  | ||||||
|         } |  | ||||||
|         _globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange); |  | ||||||
|         _globalDeviceData?.CollectDevices?.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange -= DeviceStatusChange; |  | ||||||
|         }); |  | ||||||
|         _uploadVariables = null; |  | ||||||
|         _collectDeviceRunTimes.Clear(); |  | ||||||
|         _collectVariableRunTimes.Clear(); |  | ||||||
|         _collectDeviceRunTimes = null; |  | ||||||
|         _collectVariableRunTimes = null; |  | ||||||
|         base.Dispose(disposing); |  | ||||||
|     } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         var mqttFactory = new MqttFactory(new PrivateLogger(LogMessage)); |  | ||||||
|         var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder() |  | ||||||
|             .WithDefaultEndpointBoundIPAddress(string.IsNullOrEmpty(driverPropertys.IP) ? null : IPAddress.Parse(driverPropertys.IP)) |  | ||||||
|             .WithDefaultEndpointPort(driverPropertys.Port) |  | ||||||
|             .WithDefaultEndpoint() |  | ||||||
|             .Build(); |  | ||||||
|         _mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions); |  | ||||||
|  |  | ||||||
|         _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|         _rpcCore = App.GetService<RpcSingletonService>(); |  | ||||||
|  |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|                 .Where(b => GetPropertyValue(b, nameof(variablePropertys.Enable)).GetBoolValue()) |  | ||||||
|                 .ToList(); |  | ||||||
|  |  | ||||||
|         _uploadVariables = tags; |  | ||||||
|  |  | ||||||
|         _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange += DeviceStatusChange; |  | ||||||
|         }); |  | ||||||
|         _uploadVariables.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange += VariableValueChange; |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime) |  | ||||||
|     { |  | ||||||
|         _collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task MqttServer_InterceptingPublishAsync(InterceptingPublishEventArgs arg) |  | ||||||
|     { |  | ||||||
|         if (!driverPropertys.DeviceRpcEnable || string.IsNullOrEmpty(arg.ClientId)) |  | ||||||
|             return; |  | ||||||
|         if (arg.ApplicationMessage.Topic != driverPropertys.RpcWriteTopic) |  | ||||||
|             return; |  | ||||||
|         var rpcDatas = Encoding.UTF8.GetString(arg.ApplicationMessage.PayloadSegment).FromJsonString<MqttRpcNameVaueWithId>(); |  | ||||||
|         if (rpcDatas == null) |  | ||||||
|             return; |  | ||||||
|         MqttRpcResult mqttRpcResult = new() { RpcId = rpcDatas.RpcId, Success = true }; |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             foreach (var rpcData in rpcDatas.WriteInfos) |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|                 var tag = _uploadVariables.FirstOrDefault(a => a.Name == rpcData.Key); |  | ||||||
|                 if (tag != null) |  | ||||||
|                 { |  | ||||||
|                     var rpcEnable = GetPropertyValue(tag, nameof(variablePropertys.VariableRpcEnable)).ToBoolean(); |  | ||||||
|                     if (rpcEnable == true) |  | ||||||
|                     { |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         mqttRpcResult.Success = false; |  | ||||||
|                         mqttRpcResult.Message.Add(rpcData.Key, new OperResult("权限不足,变量不支持写入")); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     mqttRpcResult.Success = false; |  | ||||||
|                     mqttRpcResult.Message.Add(rpcData.Key, new OperResult("不存在该变量")); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var result = await _rpcCore.InvokeDeviceMethodAsync(ToString() + "-" + arg.ClientId, |  | ||||||
|                 rpcDatas.WriteInfos.Where( |  | ||||||
|                 a => !mqttRpcResult.Message.Any(b => b.Key == a.Key)).ToDictionary(a => a.Key, a => a.Value)); |  | ||||||
|  |  | ||||||
|             mqttRpcResult.Message.AddRange(result); |  | ||||||
|             mqttRpcResult.Success = !mqttRpcResult.Message.Any(a => !a.Value.IsSuccess); |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             var variableMessage = new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic($"{driverPropertys.RpcSubTopic}") |  | ||||||
| .WithPayload(mqttRpcResult.ToJsonString()).Build(); |  | ||||||
|             await _mqttServer.InjectApplicationMessage( |  | ||||||
|                      new InjectedMqttApplicationMessage(variableMessage)); |  | ||||||
|         } |  | ||||||
|         catch |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Task MqttServer_InterceptingSubscriptionAsync(InterceptingSubscriptionEventArgs arg) |  | ||||||
|     { |  | ||||||
|         if (arg.TopicFilter.Topic == driverPropertys.RpcWriteTopic) |  | ||||||
|         { |  | ||||||
|             arg.Response.ReasonCode = MqttSubscribeReasonCode.UnspecifiedError; |  | ||||||
|         } |  | ||||||
|         return CompletedTask.Instance; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Task MqttServer_LoadingRetainedMessageAsync(LoadingRetainedMessagesEventArgs arg) |  | ||||||
|     { |  | ||||||
|         //首次连接时的保留消息 |  | ||||||
|         //分解List,避免超出mqtt字节大小限制 |  | ||||||
|         var varData = _globalDeviceData.AllVariables.Adapt<List<VariableData>>().ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|         var devData = _globalDeviceData.AllVariables.Adapt<List<DeviceData>>().ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|         List<MqttApplicationMessage> Messages = new(); |  | ||||||
|         foreach (var item in varData) |  | ||||||
|         { |  | ||||||
|             Messages.Add(new MqttApplicationMessageBuilder() |  | ||||||
|         .WithTopic($"{driverPropertys.VariableTopic}") |  | ||||||
|         .WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptVariableModel)).Build()); |  | ||||||
|         } |  | ||||||
|         foreach (var item in devData) |  | ||||||
|         { |  | ||||||
|             Messages.Add(new MqttApplicationMessageBuilder() |  | ||||||
| .WithTopic($"{driverPropertys.DeviceTopic}") |  | ||||||
| .WithPayload(item.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel)).Build()); |  | ||||||
|         } |  | ||||||
|         arg.LoadedRetainedMessages = Messages; |  | ||||||
|         return CompletedTask.Instance; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task MqttServer_ValidatingConnectionAsync(ValidatingConnectionEventArgs arg) |  | ||||||
|     { |  | ||||||
|         if (!arg.ClientId.StartsWith(driverPropertys.StartWithId)) |  | ||||||
|         { |  | ||||||
|             arg.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         var _openApiUserService = App.GetService<IOpenApiUserService>(); |  | ||||||
|         var userInfo = await _openApiUserService.GetUserByAccountAsync(arg.UserName);//获取用户信息 |  | ||||||
|         if (userInfo == null) |  | ||||||
|         { |  | ||||||
|             arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if (userInfo.Password != arg.Password) |  | ||||||
|         { |  | ||||||
|             arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         LogMessage?.LogInformation($"{ToString()}-{arg.ClientId}-客户端已连接成功"); |  | ||||||
|     } |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         _collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,49 +0,0 @@ | |||||||
| #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 MQTTnet.Diagnostics; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.Mqtt |  | ||||||
| { |  | ||||||
|     internal class PrivateLogger : IMqttNetLogger |  | ||||||
|     { |  | ||||||
|         readonly ILog LogMessage; |  | ||||||
|         public PrivateLogger(ILog logger) |  | ||||||
|         { |  | ||||||
|             LogMessage = logger; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public bool IsEnabled => true; |  | ||||||
|         public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception) |  | ||||||
|         { |  | ||||||
|             switch (logLevel) |  | ||||||
|             { |  | ||||||
|                 case MqttNetLogLevel.Verbose: |  | ||||||
|                     LogMessage?.Log(LogLevel.Trace, source, message != null ? (parameters != null ? message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty : message) : string.Empty, exception); |  | ||||||
|                     break; |  | ||||||
|  |  | ||||||
|                 case MqttNetLogLevel.Info: |  | ||||||
|                     LogMessage?.Log(LogLevel.Info, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception); |  | ||||||
|                     break; |  | ||||||
|  |  | ||||||
|                 case MqttNetLogLevel.Warning: |  | ||||||
|                     LogMessage?.Log(LogLevel.Warning, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception); |  | ||||||
|                     break; |  | ||||||
|  |  | ||||||
|                 case MqttNetLogLevel.Error: |  | ||||||
|                     LogMessage?.Log(LogLevel.Warning, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception); |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| #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 ThingsGateway.Components; |  | ||||||
| global using ThingsGateway.Foundation; |  | ||||||
| global using ThingsGateway.Foundation.Serial; |  | ||||||
| global using ThingsGateway.Foundation.Sockets; |  | ||||||
| global using ThingsGateway.Gateway.Application; |  | ||||||
| global using ThingsGateway.Gateway.Core; |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @using System.Net.Http |  | ||||||
| @using Microsoft.AspNetCore.Components.Forms |  | ||||||
| @using Microsoft.AspNetCore.Components.Routing |  | ||||||
| @using Microsoft.AspNetCore.Components.Web |  | ||||||
| @using Microsoft.AspNetCore.Components.Web.Virtualization |  | ||||||
| @using Microsoft.JSInterop |  | ||||||
| @using BlazorComponent |  | ||||||
| @using Masa.Blazor |  | ||||||
| @using Masa.Blazor.Presets |  | ||||||
| @using System.Net.Http.Json |  | ||||||
| @using System.IO; |  | ||||||
| @using System.Text.Json; |  | ||||||
| @using System.Reflection; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Components; |  | ||||||
| @using ThingsGateway.Admin.Core; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension.String; |  | ||||||
| @using ThingsGateway.Admin.Application; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Core; |  | ||||||
| @using ThingsGateway.Gateway.Application; |  | ||||||
| @using ThingsGateway.Gateway.Core; |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
|  |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using System.IO.Ports; |  | ||||||
| @using System.Collections.Concurrent; |  | ||||||
| @using Opc.Ua.Client; |  | ||||||
| @using Opc.Ua; |  | ||||||
| @using System.Linq; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Adapter.OPCUA; |  | ||||||
| @using Masa.Blazor |  | ||||||
| @implements IDisposable |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">设备配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.GroupSize) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.GroupSize /> |  | ||||||
|          <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.UpdateRate) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UpdateRate /> |  | ||||||
|  |  | ||||||
|          <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.DeadBand) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.DeadBand /> |  | ||||||
|          <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.KeepAliveInterval) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.KeepAliveInterval /> |  | ||||||
|  |  | ||||||
|          <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.OPCUrl) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.OPCUrl /> |  | ||||||
|          <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.UserName) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.UserName /> |  | ||||||
|          <MTextField Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.Password) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.Password /> |  | ||||||
|  |  | ||||||
|          <MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.ActiveSubscribe) Dense Outlined HideDetails="@("auto")" @bind-Value=@node.ActiveSubscribe /> |  | ||||||
|          <MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.IsUseSecurity) Dense HideDetails="@("auto")" @bind-Value=@node.IsUseSecurity /> |  | ||||||
|          <MCheckbox Class="ma-1" Label=@node.DescriptionWithOutSugar(a=>a.CheckDomain) Dense HideDetails="@("auto")" @bind-Value=@node.CheckDomain /> |  | ||||||
|  |  | ||||||
|          <MButton Class="ma-1" OnClick=@ConnectAsync Color="primary"> |  | ||||||
|              连接 |  | ||||||
|          </MButton> |  | ||||||
|  |  | ||||||
|          <MButton Class="ma-1" OnClick=@DisConnect Color="red"> |  | ||||||
|              断开 |  | ||||||
|          </MButton> |  | ||||||
|      </MRow> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @using System.Net.Http |  | ||||||
| @using Microsoft.AspNetCore.Components.Forms |  | ||||||
| @using Microsoft.AspNetCore.Components.Routing |  | ||||||
| @using Microsoft.AspNetCore.Components.Web |  | ||||||
| @using Microsoft.AspNetCore.Components.Web.Virtualization |  | ||||||
| @using Microsoft.JSInterop |  | ||||||
| @using BlazorComponent |  | ||||||
| @using Masa.Blazor |  | ||||||
| @using Masa.Blazor.Presets |  | ||||||
| @using System.Net.Http.Json |  | ||||||
| @using System.IO; |  | ||||||
| @using System.Text.Json; |  | ||||||
| @using System.Reflection; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Components; |  | ||||||
| @using ThingsGateway.Admin.Core; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension.String; |  | ||||||
| @using ThingsGateway.Admin.Application; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Core; |  | ||||||
| @using ThingsGateway.Gateway.Application; |  | ||||||
| @using ThingsGateway.Gateway.Core; |  | ||||||
| @@ -1,495 +0,0 @@ | |||||||
| #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; |  | ||||||
|  |  | ||||||
| using Mapster; |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
|  |  | ||||||
| using RabbitMQ.Client; |  | ||||||
|  |  | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Text; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; |  | ||||||
| using ThingsGateway.Foundation.Extension.Generic; |  | ||||||
| using ThingsGateway.Foundation.Extension.String; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Plugin.RabbitMQ; |  | ||||||
| /// <summary> |  | ||||||
| /// RabbitMQ |  | ||||||
| /// </summary> |  | ||||||
| public class RabbitMQClient : UpLoadBase |  | ||||||
| { |  | ||||||
|     private readonly RabbitMQClientProperty driverPropertys = new(); |  | ||||||
|     private readonly RabbitMQClientVariableProperty variablePropertys = new(); |  | ||||||
|     private ConcurrentQueue<DeviceData> _collectDeviceRunTimes = new(); |  | ||||||
|     private ConcurrentQueue<VariableData> _collectVariableRunTimes = new(); |  | ||||||
|     private IConnection _connection; |  | ||||||
|     private ConnectionFactory _connectionFactory; |  | ||||||
|     private GlobalDeviceData _globalDeviceData; |  | ||||||
|     private IModel _model; |  | ||||||
|     private RpcSingletonService _rpcCore; |  | ||||||
|     private List<DeviceVariableRunTime> _uploadVariables = new(); |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Type DriverDebugUIType => null; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override UpDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override List<DeviceVariableRunTime> UploadVariables => _uploadVariables; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override VariablePropertyBase VariablePropertys => variablePropertys; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task AfterStopAsync() |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override Task BeforStartAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return Task.CompletedTask; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private TimerTick exDeviceTimerTick; |  | ||||||
|  |  | ||||||
|     private TimerTick exVariableTimerTick; |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override async Task ExecuteAsync(CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (_model == null) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|  |  | ||||||
|                     // 创建连接 |  | ||||||
|                     _connection ??= _connectionFactory.CreateConnection(); |  | ||||||
|                     // 创建通道 |  | ||||||
|                     _model ??= _connection.CreateModel(); |  | ||||||
|                     // 声明路由队列 |  | ||||||
|                     if (driverPropertys.IsQueueDeclare) |  | ||||||
|                     { |  | ||||||
|                         _model?.QueueDeclare(driverPropertys.VariableQueueName, true, false, false); |  | ||||||
|                         _model?.QueueDeclare(driverPropertys.DeviceQueueName, true, false, false); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var varList = _collectVariableRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (varList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     if (driverPropertys.IsList) |  | ||||||
|                     { |  | ||||||
|                         var listChunk = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                         foreach (var variables in listChunk) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                 { |  | ||||||
|                                     var data = variables.GetSciptListValue(driverPropertys.BigTextScriptVariableModel); |  | ||||||
|                                     // 设置消息持久化 |  | ||||||
|                                     IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                     await Publish(driverPropertys.VariableQueueName, data, properties); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         foreach (var variable in varList) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                 { |  | ||||||
|                                     var data = variable.GetSciptListValue(driverPropertys.BigTextScriptVariableModel); |  | ||||||
|                                     // 设置消息持久化 |  | ||||||
|                                     IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                     await Publish(driverPropertys.VariableQueueName, data, properties); |  | ||||||
|                                 } |  | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     break; |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exVariableTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         var varList = _uploadVariables.Adapt<List<VariableData>>(); |  | ||||||
|                         if (varList?.Count != 0) |  | ||||||
|                         { |  | ||||||
|                             if (driverPropertys.IsList) |  | ||||||
|                             { |  | ||||||
|                                 var listChunk = varList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                                 foreach (var variables in listChunk) |  | ||||||
|                                 { |  | ||||||
|                                     try |  | ||||||
|                                     { |  | ||||||
|                                         if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                         { |  | ||||||
|                                             var data = variables.GetSciptListValue(driverPropertys.BigTextScriptVariableModel); |  | ||||||
|                                             // 设置消息持久化 |  | ||||||
|                                             IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                             await Publish(driverPropertys.VariableQueueName, data, properties); |  | ||||||
|                                         } |  | ||||||
|                                         else |  | ||||||
|                                         { |  | ||||||
|                                             break; |  | ||||||
|                                         } |  | ||||||
|                                     } |  | ||||||
|                                     catch (Exception ex) |  | ||||||
|                                     { |  | ||||||
|                                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                                     } |  | ||||||
|  |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 foreach (var variable in varList) |  | ||||||
|                                 { |  | ||||||
|                                     try |  | ||||||
|                                     { |  | ||||||
|                                         if (!cancellationToken.IsCancellationRequested) |  | ||||||
|                                         { |  | ||||||
|                                             var data = variable.GetSciptListValue(driverPropertys.BigTextScriptVariableModel); |  | ||||||
|                                             // 设置消息持久化 |  | ||||||
|                                             IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                             await Publish(driverPropertys.VariableQueueName, data, properties); |  | ||||||
|                                         } |  | ||||||
|                                         else |  | ||||||
|                                         { |  | ||||||
|                                             break; |  | ||||||
|                                         } |  | ||||||
|  |  | ||||||
|                                     } |  | ||||||
|                                     catch (Exception ex) |  | ||||||
|                                     { |  | ||||||
|                                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (!driverPropertys.IsInterval) |  | ||||||
|             { |  | ||||||
|                 ////变化推送 |  | ||||||
|                 var devList = _collectDeviceRunTimes.ToListWithDequeue(); |  | ||||||
|                 if (devList?.Count != 0) |  | ||||||
|                 { |  | ||||||
|                     if (driverPropertys.IsList) |  | ||||||
|                     { |  | ||||||
|                         var listChunk = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                         foreach (var devices in listChunk) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel); |  | ||||||
|                                 // 设置消息持久化 |  | ||||||
|                                 IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                 await Publish(driverPropertys.DeviceQueueName, data, properties); |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         foreach (var devices in devList) |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel); |  | ||||||
|                                 // 设置消息持久化 |  | ||||||
|                                 IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                 await Publish(driverPropertys.DeviceQueueName, data, properties); |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) |  | ||||||
|                             { |  | ||||||
|                                 LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (exDeviceTimerTick.IsTickHappen()) |  | ||||||
|                 { |  | ||||||
|                     var devList = _collectDevice.Adapt<List<DeviceData>>(); |  | ||||||
|                     if (devList?.Count != 0) |  | ||||||
|                     { |  | ||||||
|                         if (driverPropertys.IsList) |  | ||||||
|                         { |  | ||||||
|                             var listChunk = devList.ChunkTrivialBetter(driverPropertys.SplitSize); |  | ||||||
|                             foreach (var devices in listChunk) |  | ||||||
|                             { |  | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel); |  | ||||||
|                                     // 设置消息持久化 |  | ||||||
|                                     IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                     await Publish(driverPropertys.DeviceQueueName, data, properties); |  | ||||||
|                                 } |  | ||||||
|                                 catch (Exception ex) |  | ||||||
|                                 { |  | ||||||
|                                     LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             foreach (var devices in devList) |  | ||||||
|                             { |  | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     var data = devices.GetSciptListValue(driverPropertys.BigTextScriptDeviceModel); |  | ||||||
|                                     // 设置消息持久化 |  | ||||||
|                                     IBasicProperties properties = _model?.CreateBasicProperties(); |  | ||||||
|                                     await Publish(driverPropertys.DeviceQueueName, data, properties); |  | ||||||
|                                 } |  | ||||||
|                                 catch (Exception ex) |  | ||||||
|                                 { |  | ||||||
|                                     LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override bool IsConnected() => _connection?.IsOpen == true; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     public override string ToString() |  | ||||||
|     { |  | ||||||
|         return $" {nameof(RabbitMQClient)} IP:{driverPropertys.IP} Port:{driverPropertys.Port}"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Dispose(bool disposing) |  | ||||||
|     { |  | ||||||
|         _globalDeviceData?.AllVariables.ForEach(a => a.VariableValueChange -= VariableValueChange); |  | ||||||
|  |  | ||||||
|         _collectDevice?.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange -= DeviceStatusChange; |  | ||||||
|         }); |  | ||||||
|         _model?.SafeDispose(); |  | ||||||
|         _connection?.SafeDispose(); |  | ||||||
|         _uploadVariables = null; |  | ||||||
|         _collectDeviceRunTimes.Clear(); |  | ||||||
|         _collectVariableRunTimes.Clear(); |  | ||||||
|         _collectDeviceRunTimes = null; |  | ||||||
|         _collectVariableRunTimes = null; |  | ||||||
|     } |  | ||||||
|     private List<CollectDeviceRunTime> _collectDevice; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     protected override void Init(UploadDeviceRunTime device) |  | ||||||
|     { |  | ||||||
|         _connectionFactory = new ConnectionFactory |  | ||||||
|         { |  | ||||||
|             HostName = driverPropertys.IP, |  | ||||||
|             Port = driverPropertys.Port, |  | ||||||
|             UserName = driverPropertys.UserName, |  | ||||||
|             Password = driverPropertys.Password, |  | ||||||
|             VirtualHost = driverPropertys.VirtualHost, |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         _globalDeviceData = App.GetService<GlobalDeviceData>(); |  | ||||||
|         _rpcCore = App.GetService<RpcSingletonService>(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id)) |  | ||||||
|        .Where(b => b.VariablePropertys[device.Id].Any(c => |  | ||||||
|        { |  | ||||||
|            if (c.PropertyName == nameof(variablePropertys.Enable)) |  | ||||||
|            { |  | ||||||
|                return c.Value?.GetBoolValue() == true; |  | ||||||
|            } |  | ||||||
|            else |  | ||||||
|                return false; |  | ||||||
|        })) |  | ||||||
|        .ToList(); |  | ||||||
|  |  | ||||||
|         _uploadVariables = tags; |  | ||||||
|  |  | ||||||
|         _collectDevice = _globalDeviceData.CollectDevices.Where(a => _uploadVariables.Select(b => b.DeviceId).Contains(a.Id)).ToList(); |  | ||||||
|  |  | ||||||
|         _collectDevice.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.DeviceStatusChange += DeviceStatusChange; |  | ||||||
|             DeviceStatusChange(a); |  | ||||||
|         }); |  | ||||||
|         _uploadVariables.ForEach(a => |  | ||||||
|         { |  | ||||||
|             a.VariableValueChange += VariableValueChange; |  | ||||||
|             VariableValueChange(a); |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         if (driverPropertys.UploadInterval <= 1000) driverPropertys.UploadInterval = 1000; |  | ||||||
|         exVariableTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|         exDeviceTimerTick = new(driverPropertys.UploadInterval); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void DeviceStatusChange(CollectDeviceRunTime collectDeviceRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task Publish(string queueName, string data, IBasicProperties properties) |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             if (properties != null) |  | ||||||
|                 properties.Persistent = true; |  | ||||||
|             if (_model != null) |  | ||||||
|                 _model.BasicPublish(driverPropertys.ExchangeName, queueName, properties, Encoding.UTF8.GetBytes(data)); |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 await CacheDb.AddCacheData(queueName, data, driverPropertys.CacheMaxCount); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             //连接成功时补发缓存数据 |  | ||||||
|             var cacheData = await CacheDb.GetCacheData(10); |  | ||||||
|             foreach (var item in cacheData) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     _model?.BasicPublish(driverPropertys.ExchangeName, item.Topic, properties, Encoding.UTF8.GetBytes(item.CacheStr)); |  | ||||||
|                     LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{item.Topic}{Environment.NewLine}负载:{item.CacheStr}"); |  | ||||||
|  |  | ||||||
|                     await CacheDb.DeleteCacheData(item.Id); |  | ||||||
|                 } |  | ||||||
|                 catch |  | ||||||
|                 { |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{queueName}{Environment.NewLine}负载:{data}"); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|             LogMessage?.LogWarning(ex, ToString()); |  | ||||||
|             await CacheDb.AddCacheData(queueName, data, driverPropertys.CacheMaxCount); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime) |  | ||||||
|     { |  | ||||||
|         if (driverPropertys?.IsInterval != true) |  | ||||||
|             _collectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/S7_1200" |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension; |  | ||||||
| @using ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| @using Masa.Blazor |  | ||||||
|  |  | ||||||
| <TcpClientPage @ref=TcpClientPage></TcpClientPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Demo; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public partial class S7_1200DebugPage |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// SerialSessionPage |  | ||||||
|     /// </summary> |  | ||||||
|     private TcpClientPage TcpClientPage; |  | ||||||
|     private DriverDebugUIPage driverDebugUIPage; |  | ||||||
|  |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="firstRender"></param> |  | ||||||
|     protected override void OnAfterRender(bool firstRender) |  | ||||||
|     { |  | ||||||
|         if (firstRender) |  | ||||||
|         { |  | ||||||
|             _sections.Add(( |  | ||||||
|                 """ |  | ||||||
|                 private static async Task ModbusClientAsync() |  | ||||||
|                 { |  | ||||||
|                     //链路基础配置项 |  | ||||||
|                     var config = new TouchSocketConfig(); |  | ||||||
|                     config |  | ||||||
|                     .SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要 |  | ||||||
|                  |  | ||||||
|                 var tcpClient1 = new TcpClient();//链路对象 |  | ||||||
|                 tcpClient1.Setup(config); |  | ||||||
|  |  | ||||||
|                     //创建协议对象,构造函数需要传入对应链路对象 |  | ||||||
|                     SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500) |  | ||||||
|                 { |  | ||||||
|                     //协议配置 |  | ||||||
|                     DataFormat = DataFormat.ABCD, |  | ||||||
|                     FrameTime = 0, |  | ||||||
|                     CacheTimeout = 1000, |  | ||||||
|                     ConnectTimeOut = 3000, |  | ||||||
|                     Station = 1, |  | ||||||
|                     TimeOut = 3000, |  | ||||||
|                     IsCheckMessageId = true |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                     #region 读写测试 |  | ||||||
|                         var bytesResult = await plc.ReadAsync("400001", 20); |  | ||||||
|                         var int32sResult = await plc.ReadInt32Async("400001", 20); |  | ||||||
|  |  | ||||||
|                     #endregion |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 """, "csharp")); |  | ||||||
|  |  | ||||||
|             if (TcpClientPage != null) |  | ||||||
|                 TcpClientPage.LogAction = driverDebugUIPage.LogOut; |  | ||||||
|             _plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S1200); |  | ||||||
|             driverDebugUIPage.Plc = _plc; |  | ||||||
|  |  | ||||||
|             //初始化 |  | ||||||
|             driverDebugUIPage.Address = "M100"; |  | ||||||
|             int index = 0; |  | ||||||
|             driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++)); |  | ||||||
|             TcpClientPage.Port = 102; |  | ||||||
|             TcpClientPage.StateHasChangedAsync(); |  | ||||||
|  |  | ||||||
|             //载入配置 |  | ||||||
|             StateHasChanged(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         base.OnAfterRender(firstRender); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/S7_1500" |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension; |  | ||||||
| @using ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| @using Masa.Blazor |  | ||||||
|  |  | ||||||
| <TcpClientPage @ref=TcpClientPage></TcpClientPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Demo; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public partial class S7_1500DebugPage |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// SerialSessionPage |  | ||||||
|     /// </summary> |  | ||||||
|     private TcpClientPage TcpClientPage; |  | ||||||
|     private DriverDebugUIPage driverDebugUIPage; |  | ||||||
|  |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="firstRender"></param> |  | ||||||
|     protected override void OnAfterRender(bool firstRender) |  | ||||||
|     { |  | ||||||
|         if (firstRender) |  | ||||||
|         { |  | ||||||
|             _sections.Add(( |  | ||||||
|                 """ |  | ||||||
|                 private static async Task ModbusClientAsync() |  | ||||||
|                 { |  | ||||||
|                     //链路基础配置项 |  | ||||||
|                     var config = new TouchSocketConfig(); |  | ||||||
|                     config |  | ||||||
|                     .SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要 |  | ||||||
|                  |  | ||||||
|                 var tcpClient1 = new TcpClient();//链路对象 |  | ||||||
|                 tcpClient1.Setup(config); |  | ||||||
|  |  | ||||||
|                     //创建协议对象,构造函数需要传入对应链路对象 |  | ||||||
|                     SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500) |  | ||||||
|                 { |  | ||||||
|                     //协议配置 |  | ||||||
|                     DataFormat = DataFormat.ABCD, |  | ||||||
|                     FrameTime = 0, |  | ||||||
|                     CacheTimeout = 1000, |  | ||||||
|                     ConnectTimeOut = 3000, |  | ||||||
|                     Station = 1, |  | ||||||
|                     TimeOut = 3000, |  | ||||||
|                     IsCheckMessageId = true |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                     #region 读写测试 |  | ||||||
|                         var bytesResult = await plc.ReadAsync("400001", 20); |  | ||||||
|                         var int32sResult = await plc.ReadInt32Async("400001", 20); |  | ||||||
|  |  | ||||||
|                     #endregion |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 """, "csharp")); |  | ||||||
|  |  | ||||||
|             if (TcpClientPage != null) |  | ||||||
|                 TcpClientPage.LogAction = driverDebugUIPage.LogOut; |  | ||||||
|             _plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S1500); |  | ||||||
|             driverDebugUIPage.Plc = _plc; |  | ||||||
|  |  | ||||||
|             //初始化 |  | ||||||
|             driverDebugUIPage.Address = "M100"; |  | ||||||
|             int index = 0; |  | ||||||
|             driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++)); |  | ||||||
|             TcpClientPage.Port = 102; |  | ||||||
|             TcpClientPage.StateHasChangedAsync(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             //载入配置 |  | ||||||
|             StateHasChanged(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         base.OnAfterRender(firstRender); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/S7_200" |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension; |  | ||||||
| @using ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| @using Masa.Blazor |  | ||||||
|  |  | ||||||
| <TcpClientPage @ref=TcpClientPage></TcpClientPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Demo; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public partial class S7_200DebugPage |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// SerialSessionPage |  | ||||||
|     /// </summary> |  | ||||||
|     private TcpClientPage TcpClientPage; |  | ||||||
|     private DriverDebugUIPage driverDebugUIPage; |  | ||||||
|  |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="firstRender"></param> |  | ||||||
|     protected override void OnAfterRender(bool firstRender) |  | ||||||
|     { |  | ||||||
|         if (firstRender) |  | ||||||
|         { |  | ||||||
|             _sections.Add(( |  | ||||||
|                 """ |  | ||||||
|                 private static async Task ModbusClientAsync() |  | ||||||
|                 { |  | ||||||
|                     //链路基础配置项 |  | ||||||
|                     var config = new TouchSocketConfig(); |  | ||||||
|                     config |  | ||||||
|                     .SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要 |  | ||||||
|                  |  | ||||||
|                 var tcpClient1 = new TcpClient();//链路对象 |  | ||||||
|                 tcpClient1.Setup(config); |  | ||||||
|  |  | ||||||
|                     //创建协议对象,构造函数需要传入对应链路对象 |  | ||||||
|                     SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500) |  | ||||||
|                 { |  | ||||||
|                     //协议配置 |  | ||||||
|                     DataFormat = DataFormat.ABCD, |  | ||||||
|                     FrameTime = 0, |  | ||||||
|                     CacheTimeout = 1000, |  | ||||||
|                     ConnectTimeOut = 3000, |  | ||||||
|                     Station = 1, |  | ||||||
|                     TimeOut = 3000, |  | ||||||
|                     IsCheckMessageId = true |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                     #region 读写测试 |  | ||||||
|                         var bytesResult = await plc.ReadAsync("400001", 20); |  | ||||||
|                         var int32sResult = await plc.ReadInt32Async("400001", 20); |  | ||||||
|  |  | ||||||
|                     #endregion |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 """, "csharp")); |  | ||||||
|  |  | ||||||
|             if (TcpClientPage != null) |  | ||||||
|                 TcpClientPage.LogAction = driverDebugUIPage.LogOut; |  | ||||||
|             _plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S200); |  | ||||||
|             driverDebugUIPage.Plc = _plc; |  | ||||||
|  |  | ||||||
|             //初始化 |  | ||||||
|             driverDebugUIPage.Address = "M100"; |  | ||||||
|             int index = 0; |  | ||||||
|             driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++)); |  | ||||||
|             TcpClientPage.Port = 102; |  | ||||||
|             TcpClientPage.StateHasChangedAsync(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             //载入配置 |  | ||||||
|             StateHasChanged(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         base.OnAfterRender(firstRender); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/S7_200SMART" |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension; |  | ||||||
| @using ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| @using Masa.Blazor |  | ||||||
|  |  | ||||||
| <TcpClientPage @ref=TcpClientPage></TcpClientPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Demo; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public partial class S7_200SMARTDebugPage |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// SerialSessionPage |  | ||||||
|     /// </summary> |  | ||||||
|     private TcpClientPage TcpClientPage; |  | ||||||
|     private DriverDebugUIPage driverDebugUIPage; |  | ||||||
|  |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="firstRender"></param> |  | ||||||
|     protected override void OnAfterRender(bool firstRender) |  | ||||||
|     { |  | ||||||
|         if (firstRender) |  | ||||||
|         { |  | ||||||
|             _sections.Add(( |  | ||||||
|                 """ |  | ||||||
|                 private static async Task ModbusClientAsync() |  | ||||||
|                 { |  | ||||||
|                     //链路基础配置项 |  | ||||||
|                     var config = new TouchSocketConfig(); |  | ||||||
|                     config |  | ||||||
|                     .SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要 |  | ||||||
|                  |  | ||||||
|                 var tcpClient1 = new TcpClient();//链路对象 |  | ||||||
|                 tcpClient1.Setup(config); |  | ||||||
|  |  | ||||||
|                     //创建协议对象,构造函数需要传入对应链路对象 |  | ||||||
|                     SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500) |  | ||||||
|                 { |  | ||||||
|                     //协议配置 |  | ||||||
|                     DataFormat = DataFormat.ABCD, |  | ||||||
|                     FrameTime = 0, |  | ||||||
|                     CacheTimeout = 1000, |  | ||||||
|                     ConnectTimeOut = 3000, |  | ||||||
|                     Station = 1, |  | ||||||
|                     TimeOut = 3000, |  | ||||||
|                     IsCheckMessageId = true |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                     #region 读写测试 |  | ||||||
|                         var bytesResult = await plc.ReadAsync("400001", 20); |  | ||||||
|                         var int32sResult = await plc.ReadInt32Async("400001", 20); |  | ||||||
|  |  | ||||||
|                     #endregion |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 """, "csharp")); |  | ||||||
|  |  | ||||||
|             if (TcpClientPage != null) |  | ||||||
|                 TcpClientPage.LogAction = driverDebugUIPage.LogOut; |  | ||||||
|             _plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S200Smart); |  | ||||||
|             driverDebugUIPage.Plc = _plc; |  | ||||||
|  |  | ||||||
|             //初始化 |  | ||||||
|             driverDebugUIPage.Address = "M100"; |  | ||||||
|             int index = 0; |  | ||||||
|             driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++)); |  | ||||||
|             TcpClientPage.Port = 102; |  | ||||||
|             TcpClientPage.StateHasChangedAsync(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             //载入配置 |  | ||||||
|             StateHasChanged(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         base.OnAfterRender(firstRender); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/S7_300" |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension; |  | ||||||
| @using ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| @using Masa.Blazor |  | ||||||
|  |  | ||||||
| <TcpClientPage @ref=TcpClientPage></TcpClientPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Foundation.Demo; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// <inheritdoc/> |  | ||||||
| public partial class S7_300DebugPage |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// SerialSessionPage |  | ||||||
|     /// </summary> |  | ||||||
|     private TcpClientPage TcpClientPage; |  | ||||||
|     private DriverDebugUIPage driverDebugUIPage; |  | ||||||
|  |  | ||||||
|     private ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC _plc; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="firstRender"></param> |  | ||||||
|     protected override void OnAfterRender(bool firstRender) |  | ||||||
|     { |  | ||||||
|         if (firstRender) |  | ||||||
|         { |  | ||||||
|             _sections.Add(( |  | ||||||
|                 """ |  | ||||||
|                 private static async Task ModbusClientAsync() |  | ||||||
|                 { |  | ||||||
|                     //链路基础配置项 |  | ||||||
|                     var config = new TouchSocketConfig(); |  | ||||||
|                     config |  | ||||||
|                     .SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要 |  | ||||||
|                  |  | ||||||
|                 var tcpClient1 = new TcpClient();//链路对象 |  | ||||||
|                 tcpClient1.Setup(config); |  | ||||||
|  |  | ||||||
|                     //创建协议对象,构造函数需要传入对应链路对象 |  | ||||||
|                     SiemensS7PLC plc = new(tcpClient1,SiemensEnum.S1500) |  | ||||||
|                 { |  | ||||||
|                     //协议配置 |  | ||||||
|                     DataFormat = DataFormat.ABCD, |  | ||||||
|                     FrameTime = 0, |  | ||||||
|                     CacheTimeout = 1000, |  | ||||||
|                     ConnectTimeOut = 3000, |  | ||||||
|                     Station = 1, |  | ||||||
|                     TimeOut = 3000, |  | ||||||
|                     IsCheckMessageId = true |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                     #region 读写测试 |  | ||||||
|                         var bytesResult = await plc.ReadAsync("400001", 20); |  | ||||||
|                         var int32sResult = await plc.ReadInt32Async("400001", 20); |  | ||||||
|  |  | ||||||
|                     #endregion |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 """, "csharp")); |  | ||||||
|  |  | ||||||
|             if (TcpClientPage != null) |  | ||||||
|                 TcpClientPage.LogAction = driverDebugUIPage.LogOut; |  | ||||||
|             _plc = new ThingsGateway.Foundation.Adapter.Siemens.SiemensS7PLC(TcpClientPage.GetTcpClient(), SiemensEnum.S300); |  | ||||||
|             driverDebugUIPage.Plc = _plc; |  | ||||||
|  |  | ||||||
|             //初始化 |  | ||||||
|             driverDebugUIPage.Address = "M100"; |  | ||||||
|             int index = 0; |  | ||||||
|             driverDebugUIPage.DeviceVariableRunTimes.ForEach(a => a.VariableAddress = "M" + (100 + index++)); |  | ||||||
|             TcpClientPage.Port = 102; |  | ||||||
|             TcpClientPage.StateHasChangedAsync(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             //载入配置 |  | ||||||
|             StateHasChanged(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         base.OnAfterRender(firstRender); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/S7_400" |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.Foundation.Demo |  | ||||||
| @using BlazorComponent; |  | ||||||
| @using Microsoft.AspNetCore.Components.Web; |  | ||||||
| @using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Foundation.Adapter.Siemens; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension; |  | ||||||
| @using ThingsGateway.Foundation.Serial; |  | ||||||
|  |  | ||||||
| @using Masa.Blazor |  | ||||||
|  |  | ||||||
| <TcpClientPage @ref=TcpClientPage></TcpClientPage> |  | ||||||
|  |  | ||||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|     <div class="mb-4">驱动配置</div> |  | ||||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> |  | ||||||
|         @if (_plc != null) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.FrameTime)) Dense HideDetails="@("auto")" @bind-Value=@_plc.FrameTime></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.CacheTimeout)) Dense HideDetails="@("auto")" @bind-Value=@_plc.CacheTimeout></MTextField> |  | ||||||
|  |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.TimeOut)) Dense HideDetails="@("auto")" @bind-Value=@_plc.TimeOut></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Slot)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Slot></MTextField> |  | ||||||
|             <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(_plc.DescriptionWithOutSugar(x => x.Rack)) Dense HideDetails="@("auto")" @bind-Value=@_plc.Rack></MTextField> |  | ||||||
|  |  | ||||||
|             <MSelect Class="ma-1" Outlined Style="max-width:200px" @bind-Value="_plc.DataFormat" Label="@(_plc.DescriptionWithOutSugar(x => x.DataFormat))" |  | ||||||
|                      Items=@(typeof(DataFormat).GetEnumListWithOutSugar()) |  | ||||||
|                      MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" |  | ||||||
|                      ItemText=@((u) =>u.Description) |  | ||||||
|                      ItemValue=@(u =>(DataFormat)u.Value) |  | ||||||
|                      HideDetails=@("auto") Height="30" |  | ||||||
|                   Dense> |  | ||||||
|         </MSelect> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     </MRow> |  | ||||||
| </MCard> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <DriverDebugUIPage @ref=driverDebugUIPage Sections="_sections"> |  | ||||||
|  |  | ||||||
| </DriverDebugUIPage> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     private readonly List<(string Code, string Language)> _sections = new(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| #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.Plugin.Siemens |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public class S7_1200 : Siemens |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         /// </summary> |  | ||||||
|         public override Type DriverDebugUIType => typeof(S7_1200DebugPage); |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|         { |  | ||||||
|             if (client == null) |  | ||||||
|             { |  | ||||||
|                 FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                     ; |  | ||||||
|                 client = new TcpClient(); |  | ||||||
|                 ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|             } |  | ||||||
|             //载入配置 |  | ||||||
|             _plc = new((TcpClient)client, SiemensEnum.S1200) |  | ||||||
|             { |  | ||||||
|                 DataFormat = driverPropertys.DataFormat, |  | ||||||
|                 ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|                 TimeOut = driverPropertys.TimeOut |  | ||||||
|             }; |  | ||||||
|             if (driverPropertys.LocalTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.LocalTSAP = driverPropertys.LocalTSAP; |  | ||||||
|             } |  | ||||||
|             if (driverPropertys.DestTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.DestTSAP = driverPropertys.DestTSAP; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| #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.Plugin.Siemens |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public class S7_1500 : Siemens |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override Type DriverDebugUIType => typeof(S7_1500DebugPage); |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|         { |  | ||||||
|             if (client == null) |  | ||||||
|             { |  | ||||||
|                 FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                     ; |  | ||||||
|                 client = new TcpClient(); |  | ||||||
|                 ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|             } |  | ||||||
|             //载入配置 |  | ||||||
|             _plc = new((TcpClient)client, SiemensEnum.S1500) |  | ||||||
|             { |  | ||||||
|                 DataFormat = driverPropertys.DataFormat, |  | ||||||
|                 ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|                 TimeOut = driverPropertys.TimeOut |  | ||||||
|             }; |  | ||||||
|             if (driverPropertys.LocalTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.LocalTSAP = driverPropertys.LocalTSAP; |  | ||||||
|             } |  | ||||||
|             if (driverPropertys.DestTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.DestTSAP = driverPropertys.DestTSAP; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| #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.Plugin.Siemens |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public class S7_200 : Siemens |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override Type DriverDebugUIType => typeof(S7_200DebugPage); |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|         { |  | ||||||
|             if (client == null) |  | ||||||
|             { |  | ||||||
|                 FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                     ; |  | ||||||
|                 client = new TcpClient(); |  | ||||||
|                 ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|             } |  | ||||||
|             //载入配置 |  | ||||||
|             _plc = new((TcpClient)client, SiemensEnum.S200) |  | ||||||
|             { |  | ||||||
|                 DataFormat = driverPropertys.DataFormat, |  | ||||||
|                 ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|                 TimeOut = driverPropertys.TimeOut |  | ||||||
|             }; |  | ||||||
|             if (driverPropertys.LocalTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.LocalTSAP = driverPropertys.LocalTSAP; |  | ||||||
|             } |  | ||||||
|             if (driverPropertys.DestTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.DestTSAP = driverPropertys.DestTSAP; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,52 +0,0 @@ | |||||||
| #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.Plugin.Siemens |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public class S7_200SMART : Siemens |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override Type DriverDebugUIType => typeof(S7_200SMARTDebugPage); |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|         { |  | ||||||
|             if (client == null) |  | ||||||
|             { |  | ||||||
|                 FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                     ; |  | ||||||
|                 client = new TcpClient(); |  | ||||||
|                 ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|             } |  | ||||||
|             //载入配置 |  | ||||||
|             _plc = new((TcpClient)client, SiemensEnum.S200Smart) |  | ||||||
|             { |  | ||||||
|                 DataFormat = driverPropertys.DataFormat, |  | ||||||
|                 ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|                 TimeOut = driverPropertys.TimeOut |  | ||||||
|             }; |  | ||||||
|             if (driverPropertys.LocalTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.LocalTSAP = driverPropertys.LocalTSAP; |  | ||||||
|             } |  | ||||||
|             if (driverPropertys.DestTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.DestTSAP = driverPropertys.DestTSAP; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| #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.Plugin.Siemens |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public class S7_300 : Siemens |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override Type DriverDebugUIType => typeof(S7_300DebugPage); |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|         { |  | ||||||
|             if (client == null) |  | ||||||
|             { |  | ||||||
|                 FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                     ; |  | ||||||
|                 client = new TcpClient(); |  | ||||||
|                 ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|             } |  | ||||||
|             //载入配置 |  | ||||||
|             _plc = new((TcpClient)client, SiemensEnum.S300) |  | ||||||
|             { |  | ||||||
|                 DataFormat = driverPropertys.DataFormat, |  | ||||||
|                 ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|                 TimeOut = driverPropertys.TimeOut |  | ||||||
|             }; |  | ||||||
|             if (driverPropertys.LocalTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.LocalTSAP = driverPropertys.LocalTSAP; |  | ||||||
|             } |  | ||||||
|             if (driverPropertys.DestTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.DestTSAP = driverPropertys.DestTSAP; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| #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.Plugin.Siemens |  | ||||||
| { |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public class S7_400 : Siemens |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override Type DriverDebugUIType => typeof(S7_400DebugPage); |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public override CollectDriverPropertyBase DriverPropertys => driverPropertys; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override void Init(CollectDeviceRunTime device, object client = null) |  | ||||||
|         { |  | ||||||
|             if (client == null) |  | ||||||
|             { |  | ||||||
|                 FoundataionConfig.SetRemoteIPHost(new IPHost($"{driverPropertys.IP}:{driverPropertys.Port}")) |  | ||||||
|                     ; |  | ||||||
|                 client = new TcpClient(); |  | ||||||
|                 ((TcpClient)client).Setup(FoundataionConfig); |  | ||||||
|             } |  | ||||||
|             //载入配置 |  | ||||||
|             _plc = new((TcpClient)client, SiemensEnum.S400) |  | ||||||
|             { |  | ||||||
|                 DataFormat = driverPropertys.DataFormat, |  | ||||||
|                 ConnectTimeOut = driverPropertys.ConnectTimeOut, |  | ||||||
|                 TimeOut = driverPropertys.TimeOut |  | ||||||
|             }; |  | ||||||
|             if (driverPropertys.LocalTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.LocalTSAP = driverPropertys.LocalTSAP; |  | ||||||
|             } |  | ||||||
|             if (driverPropertys.DestTSAP != 0) |  | ||||||
|             { |  | ||||||
|                 _plc.DestTSAP = driverPropertys.DestTSAP; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @using System.Net.Http |  | ||||||
| @using Microsoft.AspNetCore.Components.Forms |  | ||||||
| @using Microsoft.AspNetCore.Components.Routing |  | ||||||
| @using Microsoft.AspNetCore.Components.Web |  | ||||||
| @using Microsoft.AspNetCore.Components.Web.Virtualization |  | ||||||
| @using Microsoft.JSInterop |  | ||||||
| @using BlazorComponent |  | ||||||
| @using Masa.Blazor |  | ||||||
| @using Masa.Blazor.Presets |  | ||||||
| @using System.Net.Http.Json |  | ||||||
| @using System.IO; |  | ||||||
| @using System.Text.Json; |  | ||||||
| @using System.Reflection; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Components; |  | ||||||
| @using ThingsGateway.Admin.Core; |  | ||||||
| @using ThingsGateway.Foundation; |  | ||||||
| @using ThingsGateway.Foundation.Extension.String; |  | ||||||
| @using ThingsGateway.Admin.Application; |  | ||||||
|  |  | ||||||
| @using ThingsGateway.Core; |  | ||||||
| @using ThingsGateway.Gateway.Application; |  | ||||||
| @using ThingsGateway.Gateway.Core; |  | ||||||
| @@ -3,48 +3,40 @@ Microsoft Visual Studio Solution File, Format Version 12.00 | |||||||
| # Visual Studio Version 17 | # Visual Studio Version 17 | ||||||
| VisualStudioVersion = 17.6.33927.249 | VisualStudioVersion = 17.6.33927.249 | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}" | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{9EB46BB6-D4EA-4B06-95EE-6C971E653030}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject | 	ProjectSection(SolutionItems) = preProject | ||||||
| 		Web\Directory.Build.props = Web\Directory.Build.props | 		admin\Directory.Build.props = admin\Directory.Build.props | ||||||
| 	EndProjectSection | 	EndProjectSection | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{4A64518E-C072-4607-BBF7-7D392CEC9D58}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}" | ||||||
|  | 	ProjectSection(SolutionItems) = preProject | ||||||
|  | 		web\Directory.Build.props = web\Directory.Build.props | ||||||
|  | 	EndProjectSection | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}" | ||||||
| 	ProjectSection(SolutionItems) = preProject | 	ProjectSection(SolutionItems) = preProject | ||||||
| 		..\.gitignore = ..\.gitignore | 		..\.gitignore = ..\.gitignore | ||||||
| 		..\README.md = ..\README.md |  | ||||||
| 	EndProjectSection | 	EndProjectSection | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "Web\ThingsGateway.Components\ThingsGateway.Components.csproj", "{799C49A4-8E23-475A-A82D-080854718BEE}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{6961511A-8787-42AF-827D-B630B2AF4791}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "Web\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{616CA361-B667-42C8-B4DC-097C7CD39830}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{268A1A81-2685-47E1-9986-5934A58A31A4}" | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "Web\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{16C62A28-BACE-4391-91F8-C2D78D063A1E}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "Web\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{8FA03089-322F-44CB-8E4B-F2637388E944}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "Web\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{14FF7150-6DB7-455B-AD00-6AB4DE37855B}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "Web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "Web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "Web\ThingsGateway.Core\ThingsGateway.Core.csproj", "{51313113-7BB8-494E-9C24-6787BECE39BB}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{79E7042F-F9E3-4D87-BFA9-4B7DD9736735}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E8D2CBBA-9BCC-44E0-B192-BA0214010203}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		.editorconfig = .editorconfig |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Foundation", "Foundation", "{B6288ADE-A570-4962-8907-991B0FF2D89C}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		Foundation\Directory.Build.props = Foundation\Directory.Build.props |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject | EndProject | ||||||
| Global | Global | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| @@ -52,58 +44,56 @@ Global | |||||||
| 		Release|Any CPU = Release|Any CPU | 		Release|Any CPU = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.Build.0 = Release|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.Build.0 = Release|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.Build.0 = Release|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.Build.0 = Release|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.Build.0 = Release|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.Build.0 = Release|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.Build.0 = Release|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.Build.0 = Release|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.Build.0 = Release|Any CPU | 		{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(NestedProjects) = preSolution | 	GlobalSection(NestedProjects) = preSolution | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891} = {B6288ADE-A570-4962-8907-991B0FF2D89C} | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE} = {BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197} | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197} | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB} = {BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} | 		{6961511A-8787-42AF-827D-B630B2AF4791} = {268A1A81-2685-47E1-9986-5934A58A31A4} | ||||||
| 		{79E7042F-F9E3-4D87-BFA9-4B7DD9736735} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} |  | ||||||
| 		{BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} |  | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution | 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||||
| 		SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB} | 		SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB} | ||||||
|   | |||||||
| @@ -1,49 +0,0 @@ | |||||||
|  |  | ||||||
| Microsoft Visual Studio Solution File, Format Version 12.00 |  | ||||||
| # Visual Studio Version 17 |  | ||||||
| VisualStudioVersion = 17.6.33927.249 |  | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "Web\ThingsGateway.Components\ThingsGateway.Components.csproj", "{799C49A4-8E23-475A-A82D-080854718BEE}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "Web\ThingsGateway.Core\ThingsGateway.Core.csproj", "{51313113-7BB8-494E-9C24-6787BECE39BB}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.UpgradeManger", "UpgradeManger\ThingsGateway.UpgradeManger\ThingsGateway.UpgradeManger.csproj", "{84362F1D-E788-4646-B555-5A3629B55EFC}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Upgrade", "UpgradeManger\ThingsGateway.Upgrade\ThingsGateway.Upgrade.csproj", "{681F774F-7B0B-450A-917C-1385E1847CA6}" |  | ||||||
| EndProject |  | ||||||
| Global |  | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution |  | ||||||
| 		Debug|Any CPU = Debug|Any CPU |  | ||||||
| 		Release|Any CPU = Release|Any CPU |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution |  | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(SolutionProperties) = preSolution |  | ||||||
| 		HideSolutionNode = FALSE |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution |  | ||||||
| 		SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB} |  | ||||||
| 	EndGlobalSection |  | ||||||
| EndGlobal |  | ||||||
| @@ -3,107 +3,107 @@ Microsoft Visual Studio Solution File, Format Version 12.00 | |||||||
| # Visual Studio Version 17 | # Visual Studio Version 17 | ||||||
| VisualStudioVersion = 17.6.33927.249 | VisualStudioVersion = 17.6.33927.249 | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.foundation\ThingsGateway.Foundation.csproj", "{2070116F-7A1B-47E2-A2F2-7BEC29ECE891}" | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Foundation", "Foundation", "{0874CBC5-C583-4FAD-BA93-94571D446898}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{0874CBC5-C583-4FAD-BA93-94571D446898}" | ||||||
| 	ProjectSection(SolutionItems) = preProject | 	ProjectSection(SolutionItems) = preProject | ||||||
| 		Foundation\Directory.Build.props = Foundation\Directory.Build.props | 		foundation\Directory.Build.props = foundation\Directory.Build.props | ||||||
| 	EndProjectSection | 	EndProjectSection | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.DLT645", "Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj", "{92963877-0185-45A5-A0EB-CEC0D55FF9B0}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.DLT645", "foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj", "{92963877-0185-45A5-A0EB-CEC0D55FF9B0}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Modbus", "Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj", "{24510CCE-0B60-4A03-9719-CF367C3528E9}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Modbus", "foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj", "{24510CCE-0B60-4A03-9719-CF367C3528E9}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCDA", "Foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj", "{566783A4-222B-46F5-AA12-0753997B3254}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCDA", "foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj", "{566783A4-222B-46F5-AA12-0753997B3254}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCUA", "Foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj", "{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.OPCUA", "foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj", "{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Siemens", "Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj", "{9695B353-D773-40DD-B65E-7B10EB0C16EC}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Adapter.Siemens", "foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj", "{9695B353-D773-40DD-B65E-7B10EB0C16EC}" | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demo", "Demo", "{95008B83-0324-4A7C-80DE-2BBDDD1A9099}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{358AE1E1-4DD6-4D1F-8935-1ACBB0111A01}" | ||||||
| 	ProjectSection(SolutionItems) = preProject | 	ProjectSection(SolutionItems) = preProject | ||||||
| 		Demo\Directory.Build.props = Demo\Directory.Build.props | 		demo\Directory.Build.props = demo\Directory.Build.props | ||||||
| 	EndProjectSection | 	EndProjectSection | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{9EB46BB6-D4EA-4B06-95EE-6C971E653030}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Photino", "demo\ThingsGateway.Foundation.Demo.Photino\ThingsGateway.Foundation.Demo.Photino.csproj", "{2192217C-CF77-422E-9E63-DF4003ABF01A}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Rcl", "demo\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj", "{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Winform", "demo\ThingsGateway.Foundation.Demo.Winform\ThingsGateway.Foundation.Demo.Winform.csproj", "{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gateway", "gateway", "{DFB97103-FC3A-4DC3-A327-DA8C65BDA607}" | ||||||
| 	ProjectSection(SolutionItems) = preProject | 	ProjectSection(SolutionItems) = preProject | ||||||
| 		Web\Directory.Build.props = Web\Directory.Build.props | 		gateway\Directory.Build.props = gateway\Directory.Build.props | ||||||
| 	EndProjectSection | 	EndProjectSection | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{4A64518E-C072-4607-BBF7-7D392CEC9D58}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}" | ||||||
|  | 	ProjectSection(SolutionItems) = preProject | ||||||
|  | 		admin\Directory.Build.props = admin\Directory.Build.props | ||||||
|  | 	EndProjectSection | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Core", "gateway\ThingsGateway.Gateway.Core\ThingsGateway.Gateway.Core.csproj", "{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Blazor", "gateway\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj", "{69EA3D89-CB40-425A-8D70-5E4A33337BE5}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Application", "gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj", "{90AB5C24-1AA3-4F58-9987-B307B92B5193}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.ApiController", "gateway\ThingsGateway.Gateway.ApiController\ThingsGateway.Gateway.ApiController.csproj", "{4C7A5A90-8292-413B-8848-419D9DCDE66F}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}" | ||||||
|  | 	ProjectSection(SolutionItems) = preProject | ||||||
|  | 		web\Directory.Build.props = web\Directory.Build.props | ||||||
|  | 	EndProjectSection | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugin", "plugin", "{E65490B8-D2E2-4693-B39C-15703B1EBFBB}" | ||||||
|  | 	ProjectSection(SolutionItems) = preProject | ||||||
|  | 		plugin\Directory.Build.props = plugin\Directory.Build.props | ||||||
|  | 	EndProjectSection | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Modbus", "plugin\ThingsGateway.Plugin.Modbus\ThingsGateway.Plugin.Modbus.csproj", "{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Mqtt", "plugin\ThingsGateway.Plugin.Mqtt\ThingsGateway.Plugin.Mqtt.csproj", "{53C870AE-0249-4485-AE63-F8A16EA4BCB4}" | ||||||
|  | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}" | ||||||
| 	ProjectSection(SolutionItems) = preProject | 	ProjectSection(SolutionItems) = preProject | ||||||
| 		..\.gitignore = ..\.gitignore | 		..\.gitignore = ..\.gitignore | ||||||
| 		..\README.md = ..\README.md | 		..\README.md = ..\README.md | ||||||
| 	EndProjectSection | 	EndProjectSection | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "Web\ThingsGateway.Components\ThingsGateway.Components.csproj", "{799C49A4-8E23-475A-A82D-080854718BEE}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "Web\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{616CA361-B667-42C8-B4DC-097C7CD39830}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLDB", "plugin\ThingsGateway.Plugin.SQLDB\ThingsGateway.Plugin.SQLDB.csproj", "{C102AB3A-377E-4753-AFA7-C13250D7DF00}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "Web\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{16C62A28-BACE-4391-91F8-C2D78D063A1E}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.QuestDB", "plugin\ThingsGateway.Plugin.QuestDB\ThingsGateway.Plugin.QuestDB.csproj", "{0DE1D254-0BD2-4D98-B939-5440BE5EB552}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "Web\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{8FA03089-322F-44CB-8E4B-F2637388E944}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.TDengineDB", "plugin\ThingsGateway.Plugin.TDengineDB\ThingsGateway.Plugin.TDengineDB.csproj", "{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "Web\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{14FF7150-6DB7-455B-AD00-6AB4DE37855B}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.RabbitMQ", "plugin\ThingsGateway.Plugin.RabbitMQ\ThingsGateway.Plugin.RabbitMQ.csproj", "{A8E68E17-4EBF-4E4C-8272-B489329A68BF}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "Web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Siemens", "plugin\ThingsGateway.Plugin.Siemens\ThingsGateway.Plugin.Siemens.csproj", "{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "Web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.DLT645", "plugin\ThingsGateway.Plugin.DLT645\ThingsGateway.Plugin.DLT645.csproj", "{AC4295F2-AB2F-4137-99EF-80FA5C83896B}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "Web\ThingsGateway.Core\ThingsGateway.Core.csproj", "{51313113-7BB8-494E-9C24-6787BECE39BB}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA", "plugin\ThingsGateway.Plugin.OPCDA\ThingsGateway.Plugin.OPCDA.csproj", "{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}" | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{79E7042F-F9E3-4D87-BFA9-4B7DD9736735}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}" | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gateway", "Gateway", "{000C3C62-345E-451C-8CEE-6F2C6A087116}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLHisAlarm", "plugin\ThingsGateway.Plugin.SQLHisAlarm\ThingsGateway.Plugin.SQLHisAlarm.csproj", "{0947E6C0-6371-4483-B0ED-191FB5073151}" | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.ApiController", "Web\ThingsGateway.Gateway.ApiController\ThingsGateway.Gateway.ApiController.csproj", "{5D7BE567-2345-46C8-9F54-DDC1DA96D198}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Application", "Web\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj", "{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Blazor", "Web\ThingsGateway.Gateway.Blazor\ThingsGateway.Gateway.Blazor.csproj", "{CD0F211A-F65B-4026-9750-68AC3C70D012}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Gateway.Core", "Web\ThingsGateway.Gateway.Core\ThingsGateway.Gateway.Core.csproj", "{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugin", "Plugin", "{CC8D0880-B73E-4DFC-9052-86504728708E}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		Plugin\Directory.Build.props = Plugin\Directory.Build.props |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Modbus", "Plugin\ThingsGateway.Plugin.Modbus\ThingsGateway.Plugin.Modbus.csproj", "{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.DLT645", "Plugin\ThingsGateway.Plugin.DLT645\ThingsGateway.Plugin.DLT645.csproj", "{A723D4D7-B796-4D97-BA68-95E5696C9559}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "Plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Mqtt", "Plugin\ThingsGateway.Plugin.Mqtt\ThingsGateway.Plugin.Mqtt.csproj", "{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA", "Plugin\ThingsGateway.Plugin.OPCDA\ThingsGateway.Plugin.OPCDA.csproj", "{7562C85D-267D-4718-8857-422B625C5BD0}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "Plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.RabbitMQ", "Plugin\ThingsGateway.Plugin.RabbitMQ\ThingsGateway.Plugin.RabbitMQ.csproj", "{503529C4-842A-47F0-928B-C8DC5B0A367D}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Siemens", "Plugin\ThingsGateway.Plugin.Siemens\ThingsGateway.Plugin.Siemens.csproj", "{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E8D2CBBA-9BCC-44E0-B192-BA0214010203}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		.editorconfig = .editorconfig |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UpgradeManger", "UpgradeManger", "{237C7BC5-7B07-40B5-AF42-CE2F8E0893C3}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		UpgradeManger\Directory.Build.props = UpgradeManger\Directory.Build.props |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.UpgradeManger", "UpgradeManger\ThingsGateway.UpgradeManger\ThingsGateway.UpgradeManger.csproj", "{84362F1D-E788-4646-B555-5A3629B55EFC}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Upgrade", "UpgradeManger\ThingsGateway.Upgrade\ThingsGateway.Upgrade.csproj", "{681F774F-7B0B-450A-917C-1385E1847CA6}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Rcl", "Demo\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj", "{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation.Demo.Photino", "Demo\ThingsGateway.Foundation.Demo.Photino\ThingsGateway.Foundation.Demo.Photino.csproj", "{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}" |  | ||||||
| EndProject | EndProject | ||||||
| Global | Global | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| @@ -135,102 +135,114 @@ Global | |||||||
| 		{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.Build.0 = Release|Any CPU | 		{9695B353-D773-40DD-B65E-7B10EB0C16EC}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{2192217C-CF77-422E-9E63-DF4003ABF01A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{2192217C-CF77-422E-9E63-DF4003ABF01A}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{2192217C-CF77-422E-9E63-DF4003ABF01A}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE}.Release|Any CPU.Build.0 = Release|Any CPU | 		{2192217C-CF77-422E-9E63-DF4003ABF01A}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830}.Release|Any CPU.Build.0 = Release|Any CPU | 		{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E}.Release|Any CPU.Build.0 = Release|Any CPU | 		{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944}.Release|Any CPU.Build.0 = Release|Any CPU | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B}.Release|Any CPU.Build.0 = Release|Any CPU | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1}.Release|Any CPU.Build.0 = Release|Any CPU | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC}.Release|Any CPU.Build.0 = Release|Any CPU | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB}.Release|Any CPU.Build.0 = Release|Any CPU | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{5D7BE567-2345-46C8-9F54-DDC1DA96D198}.Release|Any CPU.Build.0 = Release|Any CPU | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F}.Release|Any CPU.Build.0 = Release|Any CPU | 		{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{CD0F211A-F65B-4026-9750-68AC3C70D012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{CD0F211A-F65B-4026-9750-68AC3C70D012}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{CD0F211A-F65B-4026-9750-68AC3C70D012}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{CD0F211A-F65B-4026-9750-68AC3C70D012}.Release|Any CPU.Build.0 = Release|Any CPU | 		{69EA3D89-CB40-425A-8D70-5E4A33337BE5}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{5CD79F91-7182-4A9D-9BEF-4DF410C782D2}.Release|Any CPU.Build.0 = Release|Any CPU | 		{90AB5C24-1AA3-4F58-9987-B307B92B5193}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF}.Release|Any CPU.Build.0 = Release|Any CPU | 		{4C7A5A90-8292-413B-8848-419D9DCDE66F}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{A723D4D7-B796-4D97-BA68-95E5696C9559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{A723D4D7-B796-4D97-BA68-95E5696C9559}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{A723D4D7-B796-4D97-BA68-95E5696C9559}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{A723D4D7-B796-4D97-BA68-95E5696C9559}.Release|Any CPU.Build.0 = Release|Any CPU | 		{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6}.Release|Any CPU.Build.0 = Release|Any CPU | 		{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F}.Release|Any CPU.Build.0 = Release|Any CPU | 		{ECF3A7A3-2363-4A38-BC78-8FF9A8564603}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{7562C85D-267D-4718-8857-422B625C5BD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{7562C85D-267D-4718-8857-422B625C5BD0}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{7562C85D-267D-4718-8857-422B625C5BD0}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{7562C85D-267D-4718-8857-422B625C5BD0}.Release|Any CPU.Build.0 = Release|Any CPU | 		{53C870AE-0249-4485-AE63-F8A16EA4BCB4}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{A0E1EAC7-10DD-4520-973F-CC385BBFBD84}.Release|Any CPU.Build.0 = Release|Any CPU | 		{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{503529C4-842A-47F0-928B-C8DC5B0A367D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{503529C4-842A-47F0-928B-C8DC5B0A367D}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{503529C4-842A-47F0-928B-C8DC5B0A367D}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{503529C4-842A-47F0-928B-C8DC5B0A367D}.Release|Any CPU.Build.0 = Release|Any CPU | 		{C102AB3A-377E-4753-AFA7-C13250D7DF00}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{8A9F6586-3320-4F03-B3DA-09BF39AA90A0}.Release|Any CPU.Build.0 = Release|Any CPU | 		{0DE1D254-0BD2-4D98-B939-5440BE5EB552}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC}.Release|Any CPU.Build.0 = Release|Any CPU | 		{C1911F84-6FDB-4DEC-8938-69B2E3901CC4}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6}.Release|Any CPU.Build.0 = Release|Any CPU | 		{A8E68E17-4EBF-4E4C-8272-B489329A68BF}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{637A662B-7B70-4CE8-8F5F-0A095B9D77EC}.Release|Any CPU.Build.0 = Release|Any CPU | 		{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 		{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | 		{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{C5519C51-0A0C-4317-A43D-FFBB6B344ACB}.Release|Any CPU.Build.0 = Release|Any CPU | 		{AC4295F2-AB2F-4137-99EF-80FA5C83896B}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{9DA9AED3-9572-4378-A2A6-4D792D67ADDC}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
| @@ -242,33 +254,33 @@ Global | |||||||
| 		{566783A4-222B-46F5-AA12-0753997B3254} = {0874CBC5-C583-4FAD-BA93-94571D446898} | 		{566783A4-222B-46F5-AA12-0753997B3254} = {0874CBC5-C583-4FAD-BA93-94571D446898} | ||||||
| 		{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF} = {0874CBC5-C583-4FAD-BA93-94571D446898} | 		{BEFBC44A-E140-4E3E-AFBE-2DD8B98EB9BF} = {0874CBC5-C583-4FAD-BA93-94571D446898} | ||||||
| 		{9695B353-D773-40DD-B65E-7B10EB0C16EC} = {0874CBC5-C583-4FAD-BA93-94571D446898} | 		{9695B353-D773-40DD-B65E-7B10EB0C16EC} = {0874CBC5-C583-4FAD-BA93-94571D446898} | ||||||
| 		{799C49A4-8E23-475A-A82D-080854718BEE} = {BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} | 		{2192217C-CF77-422E-9E63-DF4003ABF01A} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01} | ||||||
| 		{616CA361-B667-42C8-B4DC-097C7CD39830} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{DE376FAD-1E99-4CEE-96B2-08B1D1F3D1DB} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01} | ||||||
| 		{16C62A28-BACE-4391-91F8-C2D78D063A1E} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{ACAA3F0D-CE2B-49F4-883A-ED23ADD9E325} = {358AE1E1-4DD6-4D1F-8935-1ACBB0111A01} | ||||||
| 		{8FA03089-322F-44CB-8E4B-F2637388E944} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{14FF7150-6DB7-455B-AD00-6AB4DE37855B} = {79E7042F-F9E3-4D87-BFA9-4B7DD9736735} | 		{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{2861AA39-AAAE-47ED-9ACC-4C165DDF3EF1} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{9FF2A8A6-48D0-4D8A-9EAD-1905174291CC} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{51313113-7BB8-494E-9C24-6787BECE39BB} = {BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} | 		{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{79E7042F-F9E3-4D87-BFA9-4B7DD9736735} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA} | ||||||
| 		{000C3C62-345E-451C-8CEE-6F2C6A087116} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{1A4D0B95-9FC5-4687-94E2-B6F86B5427F2} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607} | ||||||
| 		{5D7BE567-2345-46C8-9F54-DDC1DA96D198} = {000C3C62-345E-451C-8CEE-6F2C6A087116} | 		{69EA3D89-CB40-425A-8D70-5E4A33337BE5} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607} | ||||||
| 		{5CF1B3EC-84E2-484A-8DFC-2ECD2EE18E2F} = {000C3C62-345E-451C-8CEE-6F2C6A087116} | 		{90AB5C24-1AA3-4F58-9987-B307B92B5193} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607} | ||||||
| 		{CD0F211A-F65B-4026-9750-68AC3C70D012} = {000C3C62-345E-451C-8CEE-6F2C6A087116} | 		{4C7A5A90-8292-413B-8848-419D9DCDE66F} = {DFB97103-FC3A-4DC3-A327-DA8C65BDA607} | ||||||
| 		{5CD79F91-7182-4A9D-9BEF-4DF410C782D2} = {000C3C62-345E-451C-8CEE-6F2C6A087116} | 		{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197} | ||||||
| 		{BB9C2A85-7A8A-4CF9-BF44-34DE9848EC15} = {9EB46BB6-D4EA-4B06-95EE-6C971E653030} | 		{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197} | ||||||
| 		{2057E5BE-FACA-4D44-A2BA-E1F864A8DAFF} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{ECF3A7A3-2363-4A38-BC78-8FF9A8564603} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{A723D4D7-B796-4D97-BA68-95E5696C9559} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{53C870AE-0249-4485-AE63-F8A16EA4BCB4} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{D9944D52-81B4-4DBC-8C3B-2A334CCBD4F6} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{C5C89B2F-D9C9-4A67-A9BE-4E5F0B42162F} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{C102AB3A-377E-4753-AFA7-C13250D7DF00} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{7562C85D-267D-4718-8857-422B625C5BD0} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{0DE1D254-0BD2-4D98-B939-5440BE5EB552} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{A0E1EAC7-10DD-4520-973F-CC385BBFBD84} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{C1911F84-6FDB-4DEC-8938-69B2E3901CC4} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{503529C4-842A-47F0-928B-C8DC5B0A367D} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{A8E68E17-4EBF-4E4C-8272-B489329A68BF} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{8A9F6586-3320-4F03-B3DA-09BF39AA90A0} = {CC8D0880-B73E-4DFC-9052-86504728708E} | 		{5FAFD46E-6B98-4C75-B1EB-085AA18F15FD} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{84362F1D-E788-4646-B555-5A3629B55EFC} = {237C7BC5-7B07-40B5-AF42-CE2F8E0893C3} | 		{AC4295F2-AB2F-4137-99EF-80FA5C83896B} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{681F774F-7B0B-450A-917C-1385E1847CA6} = {237C7BC5-7B07-40B5-AF42-CE2F8E0893C3} | 		{9DA9AED3-9572-4378-A2A6-4D792D67ADDC} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{637A662B-7B70-4CE8-8F5F-0A095B9D77EC} = {95008B83-0324-4A7C-80DE-2BBDDD1A9099} | 		{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 		{C5519C51-0A0C-4317-A43D-FFBB6B344ACB} = {95008B83-0324-4A7C-80DE-2BBDDD1A9099} | 		{0947E6C0-6371-4483-B0ED-191FB5073151} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB} | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution | 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||||
| 		SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB} | 		SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB} | ||||||
|   | |||||||
| @@ -1,270 +0,0 @@ | |||||||
| #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.Diagnostics; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Foundation; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.Upgrade |  | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// StartCommand.txt 中配置启动主程序的指令,比如 |  | ||||||
|     /// 如果是直接启动:ThingsGateway.Web.Entry.exe |  | ||||||
|     /// 如果是WindowsService:Net Start ThingsGateway |  | ||||||
|     /// 如果是其他部署(linux,pm2等等),填写对应的启动命令 |  | ||||||
|     /// </summary> |  | ||||||
|     internal class Program |  | ||||||
|     { |  | ||||||
|         static void Main(string[] args) |  | ||||||
|         { |  | ||||||
|             //Thread.Sleep(15000); |  | ||||||
|             Thread.Sleep(5000); |  | ||||||
|             var path = args[0]; |  | ||||||
|             if (Directory.Exists(path)) |  | ||||||
|             { |  | ||||||
|                 var data = DirectoryUtility.GetDirectories(path); |  | ||||||
|                 if (data.Length == 0) |  | ||||||
|                 { |  | ||||||
|                     ConsleError($"目录{path}下不存在文件"); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     var oldFolder = $"{AppContext.BaseDirectory}FileTemp/ThingsGatewayOld/{DateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}"; |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|  |  | ||||||
|                         //复制原文件,错误时可恢复 |  | ||||||
|                         ConsleInfo($"正在备份原文件"); |  | ||||||
|                         CopyDirectory(AppContext.BaseDirectory, oldFolder, new[] { "logs", "FileTemp" }, new[] { "ThingsGateway.Upgrade" }); |  | ||||||
|                         ConsleInfo($"备份原文件成功"); |  | ||||||
|  |  | ||||||
|                         //停止主程序进程 |  | ||||||
|  |  | ||||||
|                         string filePath = $"{AppContext.BaseDirectory}ThingsGateway.Web.Entry"; |  | ||||||
|                         // 查找正在运行的进程 |  | ||||||
|                         var process = Process.GetProcesses().Where(p => |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (p.ProcessName == "ThingsGateway.Web.Entry") |  | ||||||
|                                 { |  | ||||||
|                                     return (Path.GetDirectoryName(p.MainModule.FileName) + Path.DirectorySeparatorChar).Equals(AppContext.BaseDirectory, StringComparison.OrdinalIgnoreCase); |  | ||||||
|                                     //return true; |  | ||||||
|                                 } |  | ||||||
|                                 return false; |  | ||||||
|                             } |  | ||||||
|                             catch (Exception) |  | ||||||
|                             { |  | ||||||
|                                 return false; // 进程访问被拒绝或没有主模块 |  | ||||||
|                             } |  | ||||||
|                         })?.FirstOrDefault(); |  | ||||||
|                         if (process != null) |  | ||||||
|                         { |  | ||||||
|                             var exit = process.WaitForExit(300000); |  | ||||||
|                             if (!exit) |  | ||||||
|                             { |  | ||||||
|                                 ConsleError("无法终止主程序,更新过程停止"); |  | ||||||
|  |  | ||||||
|                                 Recovery(oldFolder); |  | ||||||
|  |  | ||||||
|                                 Directory.Delete(oldFolder, true); |  | ||||||
|                                 Directory.Delete(path, true); |  | ||||||
|                                 return; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         //程序已退出 |  | ||||||
|  |  | ||||||
|                         //复制文件到主程序文件夹 |  | ||||||
|                         ConsleInfo($"正在复制文件到主程序文件夹"); |  | ||||||
|                         CopyDirectory(path, AppContext.BaseDirectory, new[] { "logs", "FileTemp" }, new[] { "ThingsGateway.Upgrade" }); |  | ||||||
|                         ConsleInfo($"复制文件到主程序文件夹成功"); |  | ||||||
|  |  | ||||||
|                         //尝试启动 |  | ||||||
|                         var dataString = FileUtil.ReadFile($"{AppContext.BaseDirectory}StartCommand.txt");//读取文件 |  | ||||||
|                         var startCommand = dataString; |  | ||||||
|                         StartCommand(startCommand); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                         Thread.Sleep(5000); |  | ||||||
|                         // 查找正在运行的进程 |  | ||||||
|                         var process1 = Process.GetProcesses().Where(p => |  | ||||||
|                         { |  | ||||||
|                             try |  | ||||||
|                             { |  | ||||||
|                                 if (p.ProcessName == "ThingsGateway.Web.Entry") |  | ||||||
|                                 { |  | ||||||
|                                     return (Path.GetDirectoryName(p.MainModule.FileName) + Path.DirectorySeparatorChar).Equals(AppContext.BaseDirectory, StringComparison.OrdinalIgnoreCase); |  | ||||||
|                                     //return true; |  | ||||||
|                                 } |  | ||||||
|                                 return false; |  | ||||||
|                             } |  | ||||||
|                             catch (Exception) |  | ||||||
|                             { |  | ||||||
|                                 return false; // 进程访问被拒绝或没有主模块 |  | ||||||
|                             } |  | ||||||
|                         })?.FirstOrDefault(); |  | ||||||
|                         if (process1 != null) |  | ||||||
|                         { |  | ||||||
|                             //代表启动正常 |  | ||||||
|                             ConsleInfo("更新成功"); |  | ||||||
|                             Directory.Delete(oldFolder, true); |  | ||||||
|                             Directory.Delete(path, true); |  | ||||||
|                             return; |  | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             //恢复原文件 |  | ||||||
|                             Recovery(oldFolder); |  | ||||||
|                             Directory.Delete(oldFolder, true); |  | ||||||
|  |  | ||||||
|                             Directory.Delete(path, true); |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|                     catch (Exception ex) |  | ||||||
|                     { |  | ||||||
|                         ConsleError(ex.ToString()); |  | ||||||
|  |  | ||||||
|                         //恢复原文件 |  | ||||||
|                         Recovery(oldFolder); |  | ||||||
|                         Directory.Delete(oldFolder, true); |  | ||||||
|                         Directory.Delete(path, true); |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 ConsleError($"不存在目录{path}"); |  | ||||||
|                 //尝试启动 |  | ||||||
|                 var dataString1 = FileUtil.ReadFile($"{AppContext.BaseDirectory}StartCommand.txt");//读取文件 |  | ||||||
|                 var startCommand1 = dataString1; |  | ||||||
|                 StartCommand(startCommand1); |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Thread.Sleep(10000); |  | ||||||
|             Console.ReadLine(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private static void Recovery(string oldFolder) |  | ||||||
|         { |  | ||||||
|             ConsleInfo("更新失败,恢复原文件"); |  | ||||||
|             CopyDirectory(oldFolder, AppContext.BaseDirectory, new[] { "logs", "FileTemp" }, new[] { "ThingsGateway.Upgrade" }); |  | ||||||
|             //尝试启动 |  | ||||||
|             var dataString1 = FileUtil.ReadFile($"{AppContext.BaseDirectory}StartCommand.txt");//读取文件 |  | ||||||
|             var startCommand1 = dataString1; |  | ||||||
|             StartCommand(startCommand1); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 复制文件夹及文件 |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="sourceFolder">原文件路径</param> |  | ||||||
|         /// <param name="destFolder">目标文件路径</param> |  | ||||||
|         /// <param name="ignoreFolder">忽略文件夹</param> |  | ||||||
|         /// <param name="ignoreFiles">忽略文件</param> |  | ||||||
|         /// <returns></returns> |  | ||||||
|         public static void CopyDirectory(string sourceFolder, string destFolder, string[] ignoreFolder, string[] ignoreFiles) |  | ||||||
|         { |  | ||||||
|             //如果目标路径不存在,则创建目标路径 |  | ||||||
|             if (!Directory.Exists(destFolder)) |  | ||||||
|             { |  | ||||||
|                 Directory.CreateDirectory(destFolder); |  | ||||||
|             } |  | ||||||
|             //得到原文件根目录下的所有文件 |  | ||||||
|             var files = Directory.GetFiles(sourceFolder); |  | ||||||
|             foreach (var file in files) |  | ||||||
|             { |  | ||||||
|                 if (ignoreFiles.Contains(Path.GetFileNameWithoutExtension(file))) |  | ||||||
|                 { continue; } |  | ||||||
|                 var name = Path.GetFileName(file); |  | ||||||
|                 var dest = Path.Combine(destFolder, name); |  | ||||||
|                 File.Copy(file, dest, true);//复制文件 |  | ||||||
|             } |  | ||||||
|             //得到原文件根目录下的所有文件夹 |  | ||||||
|             var folders = Directory.GetDirectories(sourceFolder); |  | ||||||
|             foreach (var folder in folders) |  | ||||||
|             { |  | ||||||
|                 if (ignoreFolder.Contains(Path.GetFileName(folder))) |  | ||||||
|                 { continue; } |  | ||||||
|                 var name = Path.GetFileName(folder); |  | ||||||
|                 var dest = Path.Combine(destFolder, name); |  | ||||||
|                 CopyDirectory(folder, dest, ignoreFolder, ignoreFiles);//构建目标路径,递归复制文件 |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         public static void ConsleInfo(string str) |  | ||||||
|         { |  | ||||||
|             Console.ForegroundColor = ConsoleColor.Green; |  | ||||||
|             Console.WriteLine(str); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public static void ConsleError(string str) |  | ||||||
|         { |  | ||||||
|             Console.ForegroundColor = ConsoleColor.Red; |  | ||||||
|             Console.WriteLine(str); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public static void StartCommand(string command) |  | ||||||
|         { |  | ||||||
|             // 创建进程对象 |  | ||||||
|             Process process = new Process(); |  | ||||||
|             // 设置进程启动信息 |  | ||||||
|             process.StartInfo.FileName = GetCommandInterpreter();  // 获取当前平台的命令解释器 |  | ||||||
|             process.StartInfo.Arguments = GetCommandArguments(command);  // 获取命令行参数 |  | ||||||
|             process.StartInfo.UseShellExecute = true; |  | ||||||
|             process.StartInfo.WorkingDirectory = AppContext.BaseDirectory; |  | ||||||
|             // 启动进程 |  | ||||||
|             process.Start(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 获取当前平台的命令解释器 |  | ||||||
|         static string GetCommandInterpreter() |  | ||||||
|         { |  | ||||||
|             if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) |  | ||||||
|             { |  | ||||||
|                 return "cmd.exe"; |  | ||||||
|             } |  | ||||||
|             else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux)) |  | ||||||
|             { |  | ||||||
|                 return "/bin/bash"; |  | ||||||
|             } |  | ||||||
|             else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX)) |  | ||||||
|             { |  | ||||||
|                 return "/bin/bash"; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             throw new PlatformNotSupportedException("该平台不支持执行命令行。"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 获取命令行参数 |  | ||||||
|         static string GetCommandArguments(string command) |  | ||||||
|         { |  | ||||||
|             if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) |  | ||||||
|             { |  | ||||||
|                 return $"/c {command}"; |  | ||||||
|             } |  | ||||||
|             else  // Linux 或 macOS |  | ||||||
|             { |  | ||||||
|                 return $"-c \"{command}\""; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| { |  | ||||||
|   "profiles": { |  | ||||||
|     "ThingsGateway.Upgrade": { |  | ||||||
|       "commandName": "Project", |  | ||||||
|       "commandLineArgs": "E:\\Tg\\ThingsGateway\\ThingsGateway-DEV\\framework\\Web\\ThingsGateway.Web.Entry\\bin\\Debug\\net6.0\\FileTemp\\tcp---127.0.0.1-7400-" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| Net Start ThingsGateway |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
|  |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <OutputType>Exe</OutputType> |  | ||||||
|     <ImplicitUsings>enable</ImplicitUsings> |  | ||||||
|   </PropertyGroup> |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
|   <Target Name="PostBuild" AfterTargets="PostBuildEvent"> |  | ||||||
|     <Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\"
 if not exist %25dir%25  md %25dir%25  
copy "$(TargetDir)*DLT645*.dll"  %25dir%25


" /> |  | ||||||
|   </Target> |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
|  |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <OutputType>Exe</OutputType> |  | ||||||
|     <ImplicitUsings>enable</ImplicitUsings> |  | ||||||
|   </PropertyGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   <Target Name="PostBuild" AfterTargets="PostBuildEvent"> |  | ||||||
|     <Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\"
 if not exist %25dir%25  md %25dir%25  
copy "$(TargetDir)*"  %25dir%25


" /> |  | ||||||
|   </Target> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <None Remove="StartCommand.txt" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <Compile Include="..\..\Foundation\ThingsGateway.Foundation\Foundation\Utils\FileUtil.cs" Link="FileUtil.cs" /> |  | ||||||
|     <Compile Include="..\..\Foundation\ThingsGateway.Foundation\TouchSocket\Core\Extensions\DateTimeExtensions.cs" Link="DateTimeExtensions.cs" /> |  | ||||||
|     <Compile Include="..\..\Foundation\ThingsGateway.Foundation\TouchSocket\Core\IO\DirectoryUtility.cs" Link="DirectoryUtility.cs" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   <ItemGroup> |  | ||||||
|     <Content Include="StartCommand.txt"> |  | ||||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> |  | ||||||
|     </Content> |  | ||||||
|   </ItemGroup> |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.UpgradeManger |  | ||||||
|  |  | ||||||
| <Router AppAssembly="@typeof(App).Assembly"> |  | ||||||
|     <Found Context="routeData"> |  | ||||||
|         <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> |  | ||||||
|         <FocusOnNavigate RouteData="@routeData" Selector="h1" /> |  | ||||||
|     </Found> |  | ||||||
|     <NotFound> |  | ||||||
|         <LayoutView Layout="@typeof(MainLayout)"> |  | ||||||
|             <p role="alert">Sorry, there's nothing at this address.</p> |  | ||||||
|         </LayoutView> |  | ||||||
|     </NotFound> |  | ||||||
| </Router> |  | ||||||
|  |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| [ |  | ||||||
|   { |  | ||||||
|     "Href": "/index", |  | ||||||
|     "Title": "首页" |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     "Title": "更新管理", |  | ||||||
|     "Href": "/UpgradeManger" |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| ] |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/" |  | ||||||
| @layout BaseLayout |  | ||||||
| @inject NavigationManager NavigationManager |  | ||||||
| @namespace ThingsGateway.UpgradeManger |  | ||||||
| @using Microsoft.AspNetCore.Authorization; |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     /// <param name="firstRender"></param> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     protected override async Task OnAfterRenderAsync(bool firstRender) |  | ||||||
|     { |  | ||||||
|         if (firstRender) |  | ||||||
|         { |  | ||||||
|             NavigationManager.NavigateTo("index"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         await base.OnAfterRenderAsync(firstRender); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/index" |  | ||||||
|  |  | ||||||
| <div class="ml-2"> |  | ||||||
|     <div class="my-6 "> |  | ||||||
|         <MLabel Class="text-h3" Color="primary">ThingsGateway</MLabel> |  | ||||||
|     </div> |  | ||||||
|     <div> |  | ||||||
|         <strong class="text--lighten-1 text-h5 my-1">文档</strong> |  | ||||||
|     </div> |  | ||||||
|     <div class="my-2 ml-4"> |  | ||||||
|         <PCopyableText> |  | ||||||
|             https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
|         </PCopyableText> |  | ||||||
|     </div> |  | ||||||
|     <div> |  | ||||||
|         <strong class="text--lighten-1 text-h5 my-1">协议</strong> |  | ||||||
|     </div> |  | ||||||
|     <div class="my-2 ml-4"> |  | ||||||
|         <PCopyableText Text="https://gitee.com/diego2098/ThingsGateway/blob/master/LICENSE.zh"> |  | ||||||
|             Apache-2.0开源协议 |  | ||||||
|         </PCopyableText> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div> |  | ||||||
|         <strong class="text--lighten-1 text-h5 my-1">赞助</strong> |  | ||||||
|     </div> |  | ||||||
|     <div class="my-2 ml-4"> |  | ||||||
|         <PCopyableText Text="https://diego2098.gitee.io/thingsgateway-docs/docs/donate"> |  | ||||||
|             ThingsGateway赞助途径 |  | ||||||
|         </PCopyableText> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div> |  | ||||||
|         <strong class="text--lighten-1 text-h5 my-1">社区</strong> |  | ||||||
|     </div> |  | ||||||
|     <div class="my-2 ml-4"> |  | ||||||
|         <PCopyableText Text="605534569"> |  | ||||||
|             QQ群:605534569 |  | ||||||
|         </PCopyableText> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|      |  | ||||||
|  |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| @@ -1,262 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @page "/UpgradeManger" |  | ||||||
| @namespace ThingsGateway.UpgradeManger |  | ||||||
| @using System.Linq.Expressions; |  | ||||||
| @using BlazorComponent; |  | ||||||
|  |  | ||||||
| @using Mapster; |  | ||||||
| @using Masa.Blazor.Presets; |  | ||||||
| @using System.IO; |  | ||||||
| @using Masa.Blazor; |  | ||||||
| @using Microsoft.AspNetCore.Authorization; |  | ||||||
|  |  | ||||||
| @inherits BaseComponentBase |  | ||||||
|  |  | ||||||
| @inject NavigationManager NavigationManager |  | ||||||
| @layout MainLayout |  | ||||||
| <MRow NoGutters> |  | ||||||
|     <MCol Md=@(IsShowTreeView?2:0)> |  | ||||||
|         <MSheet Show=IsShowTreeView Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")> |  | ||||||
|             <MCardTitle Class="text-body-2"> |  | ||||||
|                 当前已连接的客户端 |  | ||||||
|             </MCardTitle> |  | ||||||
|  |  | ||||||
|             <MVirtualScroll Context="item" Class="my-2" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+100}px)") OverscanCount=2 ItemSize="60" Items="TcpDmtpSocketClients"> |  | ||||||
|  |  | ||||||
|                 <ItemContent> |  | ||||||
|  |  | ||||||
|                     <MListItem OnClick=@(()=>ChoiceTcpDmtpSocketClient(item))> |  | ||||||
|                         <MListItemContent> |  | ||||||
|                             <MListItemTitle> |  | ||||||
|                                 <div class="mt-1  d-flex align-center justify-space-between" title=@($"{item.GetIPPort()} - {item.Id}")> |  | ||||||
|                                     <span>@($"{item.GetIPPort()} - {item.Id}")</span> |  | ||||||
|                                 </div> |  | ||||||
|                             </MListItemTitle> |  | ||||||
|                         </MListItemContent> |  | ||||||
|  |  | ||||||
|                     </MListItem> |  | ||||||
|  |  | ||||||
|                     <MDivider></MDivider> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 </ItemContent> |  | ||||||
|             </MVirtualScroll> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         </MSheet> |  | ||||||
|     </MCol> |  | ||||||
|     <MCol Md=@(IsShowTreeView?10:12)> |  | ||||||
|         <MButton Class="mx-1" OnClick=@(() => |  | ||||||
|                  { |  | ||||||
|                  IsShowTreeView=!IsShowTreeView; |  | ||||||
|                  } |  | ||||||
|                  ) Color="primary" Icon> |  | ||||||
|             <MIcon>mdi-menu</MIcon> |  | ||||||
|         </MButton> |  | ||||||
|         <MSheet Rounded="false" Class="pa-2" Style="width:100%"> |  | ||||||
|             <MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters> |  | ||||||
|  |  | ||||||
|                 <MCol Md="5"> |  | ||||||
|                     @if (TcpDmtpSocketClient != null && GatewayInfo != null) |  | ||||||
|                     { |  | ||||||
|                         <MSheet Class="ml-4"> |  | ||||||
|                             <MDescriptions Title="当前选择的网关" Bordered="true"> |  | ||||||
|                                 <ActionsContent> |  | ||||||
|                                     <MButton Class="text-capitalize mr-1" Color="primary" OnClick="()=>ChoiceTcpDmtpSocketClient(TcpDmtpSocketClient)"> |  | ||||||
|                                         刷新 |  | ||||||
|                                     </MButton> |  | ||||||
|                                 </ActionsContent> |  | ||||||
|                                 <ChildContent> |  | ||||||
|                                     <MDescriptionsItem Label=连接信息 Span=3>@($"{TcpDmtpSocketClient.GetIPPort()} - {TcpDmtpSocketClient.Id}")</MDescriptionsItem> |  | ||||||
|                                     <MDescriptionsItem Label=连接状态 Span=3 Class=@(!TcpDmtpSocketClient.CanSend?"red--text":"green--text")>@TcpDmtpSocketClient.CanSend</MDescriptionsItem> |  | ||||||
|                                     <MDescriptionsItem Label=更新时间 Span=3>@GatewayInfo.UpdateTime</MDescriptionsItem> |  | ||||||
|                                     <MDescriptionsItem Label=软件版本 Span=3>@GatewayInfo.Version</MDescriptionsItem> |  | ||||||
|                                     <MDescriptionsItem Label=采集设备数量 Span=3>@GatewayInfo.CollectDeviceCount</MDescriptionsItem> |  | ||||||
|                                     <MDescriptionsItem Label=上传设备数量 Span=3>@GatewayInfo.UploadDeviceCount</MDescriptionsItem> |  | ||||||
|                                     <MDescriptionsItem Label=变量数量 Span=3>@GatewayInfo.VariableCount</MDescriptionsItem> |  | ||||||
|                                 </ChildContent> |  | ||||||
|                             </MDescriptions> |  | ||||||
|                         </MSheet> |  | ||||||
|  |  | ||||||
|                         <MTabs @bind-Value="tab" Class="ma-2"> |  | ||||||
|                             <MTab Value=1>    配置更新   </MTab> |  | ||||||
|                             <MTab Value=2>     软件更新  </MTab> |  | ||||||
|                         </MTabs> |  | ||||||
|  |  | ||||||
|                         <MTabsItems Value="tab"> |  | ||||||
|                             <MTabItem Value="1"> |  | ||||||
|                                 @if (tab == 1) |  | ||||||
|                                 { |  | ||||||
|                                     <MContainer> |  | ||||||
|  |  | ||||||
|                                         <MRow Dense> |  | ||||||
|  |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|                                              <div class="m-descriptions-header__title my-2"> |  | ||||||
|                                                  导出配置信息 |  | ||||||
|                                              </div> |  | ||||||
|                                          </MCol> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                              <MButton Color="primary" Loading=isUploadLoading Disabled=disabled Class="ma-2" OnClick=@(()=>ExcelUpload())> |  | ||||||
|                                                  导出网关配置信息 |  | ||||||
|                                              </MButton> |  | ||||||
|                                          </MCol> |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                              <MButton Color="primary" Loading=isUploadLoading Disabled=disabled Class="ma-2" OnClick=@(()=>DBUpload())> |  | ||||||
|                                                  导出网关配置数据库(SQLITE) |  | ||||||
|                                              </MButton> |  | ||||||
|                                          </MCol> |  | ||||||
|  |  | ||||||
|                                      </MRow> |  | ||||||
|  |  | ||||||
|                                      <MDivider></MDivider> |  | ||||||
|  |  | ||||||
|                                      <MRow Dense> |  | ||||||
|  |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|                                              <div class="m-descriptions-header__title my-2"> |  | ||||||
|                                                  更新网关配置信息 |  | ||||||
|                                              </div> |  | ||||||
|                                          </MCol> |  | ||||||
|  |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|                                              <MFileInput Label="采集设备Excel" HideDetails=@("true") @bind-Value="_importCollectDevicesFile" Style="width:90%;" ShowSize></MFileInput> |  | ||||||
|                                              </MCol> |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsCollectDevicesFullUp /> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MFileInput Label="上传设备Excel" HideDetails=@("true") @bind-Value="_importUploadDevicesFile" Style="width:90%;" ShowSize></MFileInput> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsUploadDevicesFullUp /> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MFileInput Label="采集变量Excel" HideDetails=@("true") @bind-Value="_importDeviceVariablesFile" Style="width:90%;" ShowSize></MFileInput> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsDeviceVariablesFullUp /> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MFileInput Label="内存变量Excel" HideDetails=@("true") @bind-Value="_importMemoryVariablesFile" Style="width:90%;" ShowSize></MFileInput> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|                                                  <MSwitch Label=删除后更新 HideDetails=@("true") @bind-Value=@IsMemoryVariablesFullUp /> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                                              <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                                  <MButton Loading=isUploadLoading Disabled=disabled Class="ma-2" Color="primary" |  | ||||||
|                                                           OnClick=@(()=>ExcelDown())> |  | ||||||
|                                                      推送Excel文件 |  | ||||||
|                                                  </MButton> |  | ||||||
|                                              </MCol> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                                          </MRow> |  | ||||||
|  |  | ||||||
|                                          <MDivider></MDivider> |  | ||||||
|  |  | ||||||
|                                          <MRow Dense> |  | ||||||
|  |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|                                              <div class="m-descriptions-header__title my-2"> |  | ||||||
|                                                  重启 |  | ||||||
|                                              </div> |  | ||||||
|                                          </MCol> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                              <MButton Color="primary" Loading=isUploadLoading Disabled=disabled Class="ma-2" OnClick=@(()=>DBRestart())> |  | ||||||
|                                                  重启网关运行态 |  | ||||||
|                                              </MButton> |  | ||||||
|                                          </MCol> |  | ||||||
|                                          <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                          </MCol> |  | ||||||
|  |  | ||||||
|                                      </MRow> |  | ||||||
|  |  | ||||||
|                                  </MContainer> |  | ||||||
|  |  | ||||||
|                                 } |  | ||||||
|                             </MTabItem> |  | ||||||
|  |  | ||||||
|                             <MTabItem Value="2"> |  | ||||||
|                                 @if (tab == 2) |  | ||||||
|                                 { |  | ||||||
|  |  | ||||||
|                                     <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                         <MButton Loading=isUploadLoading Disabled=disabled Class="ma-2" Color="primary" |  | ||||||
|                                                  OnClick=@(()=>FileDown())> |  | ||||||
|                                             推送文件 |  | ||||||
|                                         </MButton> |  | ||||||
|                                     </MCol> |  | ||||||
|  |  | ||||||
|                                                                         <MCol Cols="12" Md="12"> |  | ||||||
|  |  | ||||||
|                                         <MButton Loading=isUploadLoading Disabled=disabled Class="ma-2" Color="primary" |  | ||||||
|                                                  OnClick=@(()=>FileRestart())> |  | ||||||
|                                             重启更新 |  | ||||||
|                                         </MButton> |  | ||||||
|                                     </MCol> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                                 } |  | ||||||
|                             </MTabItem> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                         </MTabsItems> |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 </MCol> |  | ||||||
|  |  | ||||||
|                 <MCol Md="7"> |  | ||||||
|                     <MCard Style="overflow-y:auto;width:100%" Elevation="0" Flat Class="ml-4"> |  | ||||||
|                          <ConsoleTxt Messages="UpgradeManger.Messages" Height=600></ConsoleTxt> |  | ||||||
|                      </MCard> |  | ||||||
|                  </MCol> |  | ||||||
|  |  | ||||||
|              </MRow> |  | ||||||
|  |  | ||||||
|          </MSheet> |  | ||||||
|  |  | ||||||
|      </MCol> |  | ||||||
|  |  | ||||||
|  </MRow> |  | ||||||
|  @code { |  | ||||||
|     StringNumber tab; |  | ||||||
|     bool IsShowTreeView = true; |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,331 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using BlazorComponent; |  | ||||||
|  |  | ||||||
| using Masa.Blazor; |  | ||||||
|  |  | ||||||
| using Microsoft.AspNetCore.Components; |  | ||||||
| using Microsoft.AspNetCore.Components.Forms; |  | ||||||
| using Microsoft.JSInterop; |  | ||||||
|  |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.IO; |  | ||||||
| using System.Linq; |  | ||||||
|  |  | ||||||
| using ThingsGateway.Core; |  | ||||||
| using ThingsGateway.Foundation; |  | ||||||
| using ThingsGateway.Foundation.Dmtp; |  | ||||||
| using ThingsGateway.Foundation.Dmtp.Rpc; |  | ||||||
| using ThingsGateway.Foundation.Rpc; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.UpgradeManger; |  | ||||||
|  |  | ||||||
| /// <summary> |  | ||||||
| /// UpgradeManger |  | ||||||
| /// </summary> |  | ||||||
| public partial class UpgradeMangerPage |  | ||||||
| { |  | ||||||
|     readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(5)); |  | ||||||
|     IBrowserFile _importCollectDevicesFile; |  | ||||||
|  |  | ||||||
|     IBrowserFile _importDeviceVariablesFile; |  | ||||||
|     IBrowserFile _importMemoryVariablesFile; |  | ||||||
|  |  | ||||||
|     IBrowserFile _importUploadDevicesFile; |  | ||||||
|  |  | ||||||
|     private bool IsCollectDevicesFullUp; |  | ||||||
|  |  | ||||||
|     private bool IsDeviceVariablesFullUp; |  | ||||||
|     private bool IsMemoryVariablesFullUp; |  | ||||||
|  |  | ||||||
|     private bool isUploadLoading; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     private bool IsUploadDevicesFullUp; |  | ||||||
|  |  | ||||||
|     private IJSObjectReference JSObjectReference; |  | ||||||
|  |  | ||||||
|     [Inject] |  | ||||||
|     IJSRuntime JSRuntime { get; set; } |  | ||||||
|  |  | ||||||
|     List<TcpDmtpSocketClient> TcpDmtpSocketClients { get; set; } |  | ||||||
|  |  | ||||||
|     [Inject] |  | ||||||
|     UpgradeManger UpgradeManger { get; set; } |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     public override void Dispose() |  | ||||||
|     { |  | ||||||
|         _periodicTimer?.Dispose(); |  | ||||||
|         base.Dispose(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// <inheritdoc/> |  | ||||||
|     /// </summary> |  | ||||||
|     protected override void OnInitialized() |  | ||||||
|     { |  | ||||||
|         _ = RunTimerAsync(); |  | ||||||
|         base.OnInitialized(); |  | ||||||
|     } |  | ||||||
|     bool disabled => TcpDmtpSocketClient?.CanSend != true; |  | ||||||
|     GatewayInfo GatewayInfo; |  | ||||||
|     TcpDmtpSocketClient TcpDmtpSocketClient; |  | ||||||
|     GatewayExcel GatewayExcel; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     async Task ExcelUpload() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             isUploadLoading = true; |  | ||||||
|  |  | ||||||
|             GatewayExcel = await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<GatewayExcel>("GetGatewayExcelAsync", InvokeOption.WaitInvoke); |  | ||||||
|  |  | ||||||
|             if (GatewayExcel.CollectDevice?.Length > 0) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     GatewayExcel.CollectDevice.Seek(0, SeekOrigin.Begin); |  | ||||||
|                     using var streamRef = new DotNetStreamReference(stream: GatewayExcel.CollectDevice); |  | ||||||
|                     JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream"); |  | ||||||
|                     await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}采集设备表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     UpgradeManger.LogMessage.LogWarning(ex, "采集设备表导出失败"); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|             if (GatewayExcel.UploadDevice?.Length > 0) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     GatewayExcel.UploadDevice.Seek(0, SeekOrigin.Begin); |  | ||||||
|                     using var streamRef = new DotNetStreamReference(stream: GatewayExcel.UploadDevice); |  | ||||||
|                     JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream"); |  | ||||||
|                     await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}上传设备表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     UpgradeManger.LogMessage.LogWarning(ex, "上传设备表导出失败"); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|             if (GatewayExcel.MemoryVariable?.Length > 0) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     GatewayExcel.MemoryVariable.Seek(0, SeekOrigin.Begin); |  | ||||||
|                     using var streamRef = new DotNetStreamReference(stream: GatewayExcel.MemoryVariable); |  | ||||||
|                     JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream"); |  | ||||||
|                     await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}内存变量表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     UpgradeManger.LogMessage.LogWarning(ex, "内存变量表导出失败"); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|             if (GatewayExcel.DeviceVariable?.Length > 0) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     GatewayExcel.DeviceVariable.Seek(0, SeekOrigin.Begin); |  | ||||||
|                     using var streamRef = new DotNetStreamReference(stream: GatewayExcel.DeviceVariable); |  | ||||||
|                     JSObjectReference ??= await JSRuntime.LoadModuleAsync("js/downloadFileFromStream"); |  | ||||||
|                     await JSObjectReference.InvokeVoidAsync("downloadFileFromStream", $"{TcpDmtpSocketClient.GetIPPort()}采集变量表导出{DateTimeExtensions.CurrentDateTime.ToString("yyyy-MM-dd HH-mm-ss-fff zz")}.xlsx", streamRef); |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|                 catch (Exception ex) |  | ||||||
|                 { |  | ||||||
|                     UpgradeManger.LogMessage.LogWarning(ex, "采集变量表导出失败"); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             await PopupService.EnqueueSnackbarAsync("上传成功", AlertTypes.Success); |  | ||||||
|         } |  | ||||||
|         finally { isUploadLoading = false; } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async Task DBUpload() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             isUploadLoading = true; |  | ||||||
|             await UpgradeManger.DBUpload(TcpDmtpSocketClient); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         finally { isUploadLoading = false; } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// 下发子网关配置 |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     private async Task ExcelDown() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             isUploadLoading = true; |  | ||||||
|             GatewayExcel gatewayExcel = new(); |  | ||||||
|             if (_importCollectDevicesFile != null) |  | ||||||
|             { |  | ||||||
|                 using var fs1 = new MemoryStream(); |  | ||||||
|                 using var stream1 = _importCollectDevicesFile.OpenReadStream(512000000); |  | ||||||
|                 await stream1.CopyToAsync(fs1); |  | ||||||
|                 fs1.Seek(0, SeekOrigin.Begin); |  | ||||||
|                 gatewayExcel.CollectDevice = fs1; |  | ||||||
|             } |  | ||||||
|             if (_importUploadDevicesFile != null) |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|                 using var fs2 = new MemoryStream(); |  | ||||||
|                 using var stream2 = _importUploadDevicesFile.OpenReadStream(512000000); |  | ||||||
|                 await stream2.CopyToAsync(fs2); |  | ||||||
|                 fs2.Seek(0, SeekOrigin.Begin); |  | ||||||
|                 gatewayExcel.UploadDevice = fs2; |  | ||||||
|             } |  | ||||||
|             if (_importDeviceVariablesFile != null) |  | ||||||
|             { |  | ||||||
|                 using var fs3 = new MemoryStream(); |  | ||||||
|                 using var stream3 = _importDeviceVariablesFile.OpenReadStream(512000000); |  | ||||||
|                 await stream3.CopyToAsync(fs3); |  | ||||||
|                 fs3.Seek(0, SeekOrigin.Begin); |  | ||||||
|                 gatewayExcel.DeviceVariable = fs3; |  | ||||||
|             } |  | ||||||
|             if (_importMemoryVariablesFile != null) |  | ||||||
|             { |  | ||||||
|                 using var fs4 = new MemoryStream(); |  | ||||||
|                 using var stream4 = _importMemoryVariablesFile.OpenReadStream(512000000); |  | ||||||
|                 await stream4.CopyToAsync(fs4); |  | ||||||
|                 fs4.Seek(0, SeekOrigin.Begin); |  | ||||||
|                 gatewayExcel.MemoryVariable = fs4; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var result = await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<OperResult>("SetGatewayExcelAsync", new InvokeOption(30000), gatewayExcel); |  | ||||||
|             if (result.IsSuccess) |  | ||||||
|             { |  | ||||||
|                 await PopupService.EnqueueSnackbarAsync("更新成功", AlertTypes.Success); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 await PopupService.EnqueueSnackbarAsync(result.Message, AlertTypes.Error); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (Exception ex) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             await PopupService.EnqueueSnackbarAsync(ex.Message, AlertTypes.Error); |  | ||||||
|         } |  | ||||||
|         finally |  | ||||||
|         { |  | ||||||
|             isUploadLoading = false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     private async Task FileDown() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             isUploadLoading = true; |  | ||||||
|             var data = Program.app.MainWindow.ShowOpenFolder("选择更新文件夹", AppContext.BaseDirectory); |  | ||||||
|             if (data.Length > 0) |  | ||||||
|             { |  | ||||||
|                 await Task.Run(async () => |  | ||||||
|                 { |  | ||||||
|                     await UpgradeManger.FileDown(TcpDmtpSocketClient, data.FirstOrDefault()); |  | ||||||
|                 } |  | ||||||
|                 ); |  | ||||||
|                 await PopupService.EnqueueSnackbarAsync("推送成功", AlertTypes.Success); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|         finally { isUploadLoading = false; } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task FileRestart() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             isUploadLoading = true; |  | ||||||
|             var confirm = await PopupService.ConfirmAsync("重启", "网关重启,会暂时断开连接,会在约1分钟后重新连接 ?", AlertTypes.Warning); |  | ||||||
|             if (confirm) |  | ||||||
|             { |  | ||||||
|                 await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<OperResult>("FileRestart", InvokeOption.WaitSend); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         finally |  | ||||||
|         { |  | ||||||
|             isUploadLoading = false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// DBRestart |  | ||||||
|     /// </summary> |  | ||||||
|     /// <returns></returns> |  | ||||||
|     private async Task DBRestart() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             isUploadLoading = true; |  | ||||||
|             await TcpDmtpSocketClient.GetDmtpRpcActor().InvokeTAsync<OperResult>("DBRestartAsync", new InvokeOption(30000)); |  | ||||||
|             await PopupService.EnqueueSnackbarAsync("重启成功", AlertTypes.Success); |  | ||||||
|         } |  | ||||||
|         finally |  | ||||||
|         { |  | ||||||
|             isUploadLoading = false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     async Task ChoiceTcpDmtpSocketClient(TcpDmtpSocketClient item) |  | ||||||
|     { |  | ||||||
|         TcpDmtpSocketClient = item; |  | ||||||
|         GatewayInfo = await item.GetDmtpRpcActor().InvokeTAsync<GatewayInfo>("GetGatewayInfo", InvokeOption.WaitInvoke); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task RefreshAsync() |  | ||||||
|     { |  | ||||||
|         await Task.CompletedTask; |  | ||||||
|         TcpDmtpSocketClients = UpgradeManger.TcpDmtpService.GetClients().ToList(); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private async Task RunTimerAsync() |  | ||||||
|     { |  | ||||||
|         await RefreshAsync(); |  | ||||||
|         while (await _periodicTimer.WaitForNextTickAsync()) |  | ||||||
|         { |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 await RefreshAsync(); |  | ||||||
|                 await InvokeAsync(StateHasChanged); |  | ||||||
|             } |  | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,49 +0,0 @@ | |||||||
| #region copyright |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| #endregion |  | ||||||
|  |  | ||||||
| using Microsoft.Extensions.DependencyInjection; |  | ||||||
|  |  | ||||||
| using Photino.Blazor; |  | ||||||
|  |  | ||||||
| namespace ThingsGateway.UpgradeManger; |  | ||||||
|  |  | ||||||
| internal class Program |  | ||||||
| { |  | ||||||
|     internal static PhotinoBlazorApp app; |  | ||||||
|     [STAThread] |  | ||||||
|     private static void Main(string[] args) |  | ||||||
|     { |  | ||||||
|         System.IO.Directory.SetCurrentDirectory(AppContext.BaseDirectory); |  | ||||||
|  |  | ||||||
|         var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args); |  | ||||||
|  |  | ||||||
|         appBuilder.RootComponents.Add<App>("#app"); |  | ||||||
|         appBuilder.Services.ThingsGatewayComponentsConfigureServices(); |  | ||||||
|         appBuilder.Services.AddSingleton<UpgradeManger>(); |  | ||||||
|  |  | ||||||
|         app = appBuilder.Build(); |  | ||||||
|         app.MainWindow.SetTitle("ThingsGateway.UpgradeManger"); |  | ||||||
|         app.MainWindow.SetIconFile("wwwroot/favicon.ico"); |  | ||||||
|         AppDomain.CurrentDomain.UnhandledException += (sender, error) => |  | ||||||
|         { |  | ||||||
|         }; |  | ||||||
|         CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); |  | ||||||
|         var upgradeManger = app.Services.GetService<UpgradeManger>(); |  | ||||||
|         _ = upgradeManger.ExecuteAsync(cancellationTokenSource.Token); |  | ||||||
|         app.Run(); |  | ||||||
|  |  | ||||||
|         cancellationTokenSource.Cancel(); |  | ||||||
|         cancellationTokenSource.Dispose(); |  | ||||||
|  |  | ||||||
|         Thread.Sleep(2000); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.UpgradeManger |  | ||||||
| @inherits LayoutComponentBase |  | ||||||
|  |  | ||||||
| <CascadingValue Value="IsMobile" Name="IsMobile"> |  | ||||||
|     <MApp> |  | ||||||
|         <MErrorHandler> |  | ||||||
|             @Body |  | ||||||
|         </MErrorHandler> |  | ||||||
|     </MApp> |  | ||||||
| </CascadingValue> |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|     public bool IsMobile { get; set; } |  | ||||||
|     [Inject] |  | ||||||
|     public MasaBlazor MasaBlazor { get; set; } |  | ||||||
|     protected override void OnInitialized() |  | ||||||
|     { |  | ||||||
|         base.OnInitialized(); |  | ||||||
|         MasaBlazor.BreakpointChanged += BreakpointOnOnUpdate; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void BreakpointOnOnUpdate(object sender, BreakpointChangedEventArgs e) |  | ||||||
|     { |  | ||||||
|         IsMobile = MasaBlazor.Breakpoint.Mobile; |  | ||||||
|         if (e.MobileChanged) |  | ||||||
|         { |  | ||||||
|             StateHasChanged(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| @* |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 |  | ||||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 |  | ||||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 |  | ||||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway |  | ||||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway |  | ||||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ |  | ||||||
| //  QQ群:605534569 |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
| *@ |  | ||||||
|  |  | ||||||
| @namespace ThingsGateway.UpgradeManger |  | ||||||
| @using System.Text; |  | ||||||
| @inherits LayoutComponentBase |  | ||||||
| @layout BaseLayout |  | ||||||
|  |  | ||||||
| <PPageTabsProvider> |  | ||||||
|  |  | ||||||
|     <CascadingValue Value="@this" IsFixed> |  | ||||||
|         <CascadingValue Value="@Changed" Name="Changed"> |  | ||||||
|  |  | ||||||
|             <MNavigationDrawer Color="barcolor" @bind-Value="_drawerOpen" App Width="200"> |  | ||||||
|                 <Logo CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT  CONFIG_TITLE=@CONFIG_TITLE HeightInt=@(IsMobile?BlazorResourceConst.AppBarHeight:BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight) /> |  | ||||||
|                 <AppList ClassString="overflow-y-auto" Routable |  | ||||||
|                          StyleString=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight}px);") |  | ||||||
|                          Items="Navs" /> |  | ||||||
|             </MNavigationDrawer> |  | ||||||
|  |  | ||||||
|             <MAppBar Color="barcolor" Style=@($"{(!(IsMobile||_drawerOpen!=true)? "left:200px;":"")}") Elevation="1" App Flat ClippedRight Dense ElevateOnScroll |  | ||||||
|                      MaxHeight="@(BlazorResourceConst.AppBarHeight)" Height="@(BlazorResourceConst.AppBarHeight)"> |  | ||||||
|                 <MButton Class="mr-0" Icon Small=IsMobile OnClick=@(() => _drawerOpen = !_drawerOpen)> |  | ||||||
|                     <MIcon>mdi-menu</MIcon> |  | ||||||
|                 </MButton> |  | ||||||
|  |  | ||||||
|             </MAppBar> |  | ||||||
|  |  | ||||||
|             <MMain Style=@($"{(!(IsMobile||_drawerOpen!=true)? "padding-left:200px;":"")}")> |  | ||||||
|                 <div class="full-width"> |  | ||||||
|                     <PageTabs @ref="_pageTabs" PageTabItems="pageTabItems" /> |  | ||||||
|                 </div> |  | ||||||
|                 <MDivider Center></MDivider> |  | ||||||
|                 <MCard Flat Class="overflow-y-auto overflow-x-hidden ma-auto pa-0 rounded-0" Style=@($"height: calc(100vh - {BlazorResourceConst.AppBarHeight+BlazorResourceConst.PageTabsHeight+BlazorResourceConst.FooterHeight}px);")> |  | ||||||
|                     <PPageContainer PageTabs="@_pageTabs?.PPageTabs"> |  | ||||||
|                         @Body |  | ||||||
|                     </PPageContainer> |  | ||||||
|                 </MCard> |  | ||||||
|                 <MSheet Class="d-flex justify-center align-center rounded-0" Style=@($"height: {BlazorResourceConst.FooterHeight}px;")> |  | ||||||
|                     <Foter CONFIG_COPYRIGHT=@CONFIG_COPYRIGHT CONFIG_COPYRIGHT_URL=@CONFIG_COPYRIGHT_URL CONFIG_TITLE=@CONFIG_TITLE></Foter> |  | ||||||
|                 </MSheet> |  | ||||||
|             </MMain> |  | ||||||
|         </CascadingValue> |  | ||||||
|     </CascadingValue> |  | ||||||
|  |  | ||||||
| </PPageTabsProvider> |  | ||||||
| @code { |  | ||||||
|     bool Changed { get; set; } |  | ||||||
|     private bool? _drawerOpen = true; |  | ||||||
|  |  | ||||||
|     private PageTabs _pageTabs; |  | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// IsMobile |  | ||||||
|     /// </summary> |  | ||||||
|     [CascadingParameter(Name = "IsMobile")] |  | ||||||
|     public bool IsMobile { get; set; } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @code { |  | ||||||
|  |  | ||||||
|     private string CONFIG_COPYRIGHT = "Diego"; |  | ||||||
|  |  | ||||||
|     private string CONFIG_COPYRIGHT_URL = "https://gitee.com/diego2098/ThingsGateway"; |  | ||||||
|  |  | ||||||
|     private string CONFIG_TITLE = "ThingsGateway"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @code { |  | ||||||
|  |  | ||||||
|     private List<NavItem> Navs { get; set; } = new(); |  | ||||||
|     private List<PageTabItem> pageTabItems { get; set; } = new(); |  | ||||||
|     protected override void OnInitialized() |  | ||||||
|     { |  | ||||||
|         var dataString =FileUtil. ReadFile($"{AppContext.BaseDirectory}Navs.json");//读取文件 |  | ||||||
|         Navs=dataString.FromJsonString<List<NavItem>>(); |  | ||||||
|         pageTabItems = Navs.PasePageTabItem(); |  | ||||||
|         base.OnInitialized(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk.Razor"> |  | ||||||
|  |  | ||||||
| 	<PropertyGroup> |  | ||||||
| 		<OutputType>WinExe</OutputType> |  | ||||||
| 		<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon> |  | ||||||
| 	</PropertyGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<PackageReference Include="Photino.Blazor" Version="2.6.0" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> |  | ||||||
| 		<ProjectReference Include="..\..\Web\ThingsGateway.Components\ThingsGateway.Components.csproj" /> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<Content Update="wwwroot\**"> |  | ||||||
| 			<CopyToOutputDirectory>Always</CopyToOutputDirectory> |  | ||||||
| 		</Content> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
| 	<ItemGroup> |  | ||||||
| 		<Content Update="Navs.json"> |  | ||||||
| 			<CopyToOutputDirectory>Always</CopyToOutputDirectory> |  | ||||||
| 		</Content> |  | ||||||
| 		<Content Update="UpgradeMangerConfig.json"> |  | ||||||
| 			<CopyToOutputDirectory>Always</CopyToOutputDirectory> |  | ||||||
| 		</Content> |  | ||||||
| 	</ItemGroup> |  | ||||||
|  |  | ||||||
| </Project> |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user