mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-31 07:33:58 +08:00 
			
		
		
		
	Compare commits
	
		
			2067 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 541c60b363 | ||
|   | 824e95f7cb | ||
|   | 38f7850196 | ||
|   | bef9de88e2 | ||
|   | 48cd5e7c7f | ||
|   | 3b44fda51c | ||
|   | dbfc9a5bb4 | ||
|   | 1b758aa41a | ||
|   | 43bdc70899 | ||
|   | fadda000a6 | ||
|   | 45a8c91a5a | ||
|   | 8e938f18be | ||
|   | ab1b364c54 | ||
|   | 5ec65b2fb0 | ||
|   | 926eced724 | ||
|   | f7f8802272 | ||
|   | c6910dff02 | ||
|   | ad299d0dbb | ||
|   | 8b124d1050 | ||
|   | ff41080dbd | ||
|   | 0e28606e3d | ||
|   | 6a025ceee5 | ||
|   | 6b2e53d6dc | ||
|   | b989aa5561 | ||
|   | f5b0b7ebd2 | ||
|   | 16881ae076 | ||
|   | af04112656 | ||
|   | a2863112dc | ||
|   | f531e4dfc5 | ||
|   | 8db9b32ba7 | ||
|   | dd5691cbef | ||
|   | de48b32af3 | ||
|   | 600b5042a1 | ||
|   | aac77029da | ||
|   | e50205f557 | ||
|   | e227411d1f | ||
|   | 2de0ed793f | ||
|   | cb0276f273 | ||
|   | 562b3f17c9 | ||
|   | 0f78f81c1c | ||
|   | 6594937d0a | ||
|   | 64bc6084be | ||
|   | 20434d5bd2 | ||
|   | 9ecc9380e6 | ||
|   | a57c55080b | ||
|   | b8ca06c6be | ||
|   | 5aff6461a1 | ||
|   | 6cf53fefec | ||
|   | 45132f3503 | ||
|   | f1e78a0e8a | ||
|   | 0bf28ec275 | ||
|   | 41f8412c97 | ||
|   | c535974362 | ||
|   | 1860c5f215 | ||
|   | 6d778b2d39 | ||
|   | f48b99c259 | ||
|   | 3c73b93051 | ||
|   | 98f3f2d519 | ||
|   | b76b4e8d68 | ||
|   | 07285a7c61 | ||
|   | 03c0dfef37 | ||
|   | 6ef6929c35 | ||
|   | e3c0c173f0 | ||
|   | 7d64e058d4 | ||
|   | e97ee9b64b | ||
|   | 6a03e39eeb | ||
|   | 525ec740b5 | ||
|   | b790cf5f4e | ||
|   | d1248811fd | ||
|   | 022d016e8e | ||
|   | f73245e650 | ||
|   | 484461fa05 | ||
|   | 7e0b7aff2a | ||
|   | 6c450dcb09 | ||
|   | 227f44283f | ||
|   | 74f6e79625 | ||
|   | cec43e2ce8 | ||
|   | 7553b258bb | ||
|   | 8bdbdc117e | ||
|   | 0e206be296 | ||
|   | 00b7353433 | ||
|   | 44e7a83593 | ||
|   | dd68d555d4 | ||
|   | 0456296103 | ||
|   | a1b66277ff | ||
|   | 50758b79bc | ||
|   | 06a1f902ad | ||
|   | 58f8b23b7c | ||
|   | 9e7c348b15 | ||
|   | 5f5ff8b43b | ||
|   | f626b4e5fc | ||
|   | bc23200e66 | ||
|   | 95ab59fd5a | ||
|   | 0bbee003b0 | ||
|   | d20cb7a928 | ||
|   | 952c134aba | ||
|   | 5533d980e3 | ||
|   | aa0213818f | ||
|   | af88ffd57c | ||
|   | 87447b1c2a | ||
|   | 384a12880b | ||
|   | 791f91f377 | ||
|   | 4f8b405cc3 | ||
|   | e1b7af201a | ||
|   | a04b7817a9 | ||
|   | 21bf83aec7 | ||
|   | d060d5179d | ||
|   | e73dd58e46 | ||
|   | a34e4a6942 | ||
|   | a7ee6d78b5 | ||
|   | 0a6651ac11 | ||
|   | fa25053c13 | ||
|   | 61dd4edeb5 | ||
|   | dbaeff302b | ||
|   | 6cbe7ebcf2 | ||
|   | 2826e08c8c | ||
|   | e30e337efa | ||
|   | 39788e0357 | ||
|   | c47363df71 | ||
|   | 4199453038 | ||
|   | db991081c8 | ||
|   | 24f946a727 | ||
|   | 772dae047a | ||
|   | 020f440fdd | ||
|   | c88fc5ec09 | ||
|   | 475849fbef | ||
|   | 1d63228fb2 | ||
|   | c918c0c010 | ||
|   | 1028179983 | ||
|   | 686f61ff90 | ||
|   | ae43fadca3 | ||
|   | 1bf05780b3 | ||
|   | 3e30daa1d3 | ||
|   | 54ef1233b1 | ||
|   | 4413633de7 | ||
|   | c76e20d146 | ||
|   | 36d53b7ce4 | ||
|   | 0b0bce2761 | ||
|   | d47a9be03c | ||
|   | bc32d7ae7a | ||
|   | e6747a2c2c | ||
|   | 3fb48cb64e | ||
|   | 381db1cf53 | ||
|   | d3939aeb9d | ||
|   | 5956f90557 | ||
|   | 7f54ecfe5d | ||
|   | e7bda99c8b | ||
|   | ea7ab5a2bf | ||
|   | ee566d199a | ||
|   | 56eca454b1 | ||
|   | d057974c3e | ||
|   | 9514e7fdea | ||
|   | e546113873 | ||
|   | 60f1139355 | ||
|   | 1b18b59054 | ||
|   | afec0187e9 | ||
|   | d0d7e1ccf8 | ||
|   | d72376b4b7 | ||
|   | 3be60cb305 | ||
|   | 75b1f351a1 | ||
|   | 07185f8018 | ||
|   | 2f081b62a7 | ||
|   | bbce2a11e1 | ||
|   | 96ab609157 | ||
|   | d961d56a35 | ||
|   | 82a5335a92 | ||
|   | 729a23949c | ||
|   | a1b0419d7a | ||
|   | 7a23015b9d | ||
|   | 9cbe0dbae1 | ||
|   | 4f139b7d03 | ||
|   | 1e925e2560 | ||
|   | a42e1e3af3 | ||
|   | 799caec7ee | ||
|   | dd7d30498f | ||
|   | e9b1720e98 | ||
|   | 5f41371bdb | ||
|   | 5226bfae20 | ||
|   | d1eab168b7 | ||
|   | 8760518c10 | ||
|   | 6719a352c2 | ||
|   | 8449b6c6b8 | ||
|   | 0550eaf465 | ||
|   | bdc9eb44ec | ||
|   | 37b99cb1b0 | ||
|   | 492381e4fc | ||
|   | 27d65dd799 | ||
|   | 434724310c | ||
|   | e5ad5a8521 | ||
|   | 3942819fed | ||
|   | 1cc5f538aa | ||
|   | b0d8534ea4 | ||
|   | 5b2bc38670 | ||
|   | b36aa3557c | ||
|   | a1a525e6e3 | ||
|   | 14453cc437 | ||
|   | db760ba5d8 | ||
|   | 4ae692008f | ||
|   | f37449f9ac | ||
|   | 8b7348b3d4 | ||
|   | 709cbb7b2e | ||
|   | 187f1a4ce2 | ||
|   | 0f2ebd3a54 | ||
|   | 86b63c2792 | ||
|   | cec2e71b41 | ||
|   | 9380f3e1ec | ||
|   | 76c2934e12 | ||
|   | 9714c35d4b | ||
|   | 0d9beb713a | ||
|   | c5f8d0e0b7 | ||
|   | 5e8f4b075d | ||
|   | 4b53fca3db | ||
|   | 5d9c030a09 | ||
|   | bacbb9a28e | ||
|   | 7c287e0c03 | ||
|   | 10f675137d | ||
|   | 6bdb5328e3 | ||
|   | 14f529ac4e | ||
|   | ffe96d9ef1 | ||
|   | 335f264caa | ||
|   | b73e86ea9f | ||
|   | 2bc2c4c57b | ||
|   | 6f87c2f03a | ||
|   | 75e677af88 | ||
|   | 9ffe355396 | ||
|   | 60b0fb23f8 | ||
|   | 1c05ffc6ed | ||
|   | 8cd4e43c68 | ||
|   | 8486d28310 | ||
|   | e8aadda185 | ||
|   | fcfd0428ab | ||
|   | ddcc087800 | ||
|   | d574de54b4 | ||
|   | 1682ac03ac | ||
|   | 447dbece1c | ||
|   | dcca901b17 | ||
|   | a32c779074 | ||
|   | 187c0f9829 | ||
|   | 6c970c88ab | ||
|   | 28a4520c77 | ||
|   | 02d0dcdff7 | ||
|   | 427d4e31c9 | ||
|   | c60f7aac44 | ||
|   | 42a7758a34 | ||
|   | e0bade4670 | ||
|   | 6af83152de | ||
|   | 091a30045d | ||
|   | b2c8ae0c33 | ||
|   | 8b6e0982c6 | ||
|   | caa3ebd600 | ||
|   | d248e047b3 | ||
|   | 25a95a1de0 | ||
|   | d506b2c692 | ||
|   | 24c672c2b9 | ||
|   | c407e0e83e | ||
|   | b1346698d6 | ||
|   | 5c01129567 | ||
|   | cd7ce53bd0 | ||
|   | 4c95c20061 | ||
|   | 5339db5058 | ||
|   | 623e932f8c | ||
|   | 43659de4f4 | ||
|   | 2a661eda42 | ||
|   | c85a93a17b | ||
|   | 8ab36cb3e1 | ||
|   | 72820d0708 | ||
|   | 95b551d4ba | ||
|   | 68af9a0695 | ||
|   | 6953c3989b | ||
|   | cd4cb385d5 | ||
|   | f4f6d595fc | ||
|   | d2356f00e9 | ||
|   | e408136196 | ||
|   | c355968add | ||
|   | 783f878947 | ||
|   | 4faf41e482 | ||
|   | d8964b6ed2 | ||
|   | b5b999941c | ||
|   | deeba8c4de | ||
|   | 9e48729eb0 | ||
|   | 936e374c05 | ||
|   | 0f3524b114 | ||
|   | d62de3d72c | ||
|   | 957a80da4b | ||
|   | 1dccd70f7c | ||
|   | 006a5d4e61 | ||
|   | ce7cdcf54e | ||
|   | c1ebb4a79b | ||
|   | 41964ae1de | ||
|   | 66cf34adf7 | ||
|   | 9e9e0009cf | ||
|   | d5cd9660fc | ||
|   | 12a7803653 | ||
|   | 8f7bef6a20 | ||
|   | a0715b830c | ||
|   | f87ce10dc4 | ||
|   | ee4936b8c9 | ||
|   | 3cb2592660 | ||
|   | 574c901b40 | ||
|   | 7590ba4ad5 | ||
|   | 39ce18f8bb | ||
|   | 777a4f9d3f | ||
|   | b91a938787 | ||
|   | c903abdb1b | ||
|   | 3279bc0580 | ||
|   | bd32c9f49e | ||
|   | 5507088e3d | ||
|   | 37ad48ae4a | ||
|   | 120c6e6d87 | ||
|   | 866e907b7e | ||
|   | 2bd8c2cb10 | ||
|   | c6c9919178 | ||
|   | 575bf9d1e0 | ||
|   | 82a56e0285 | ||
|   | 25d5f7c132 | ||
|   | a3e9ecf30f | ||
|   | ec5ff0a07f | ||
|   | be836d30c5 | ||
|   | 42b1529a5f | ||
|   | 47708c4807 | ||
|   | d2a51e004c | ||
|   | ab14230101 | ||
|   | 4bcf8c1f78 | ||
|   | 44d00e9da3 | ||
|   | d7e6a4493c | ||
|   | 53e89d8c54 | ||
|   | 4497c13634 | ||
|   | 4a35fade46 | ||
|   | 6cba0601fd | ||
|   | ed4332ea78 | ||
|   | aba069cec5 | ||
|   | 8a82ac0a11 | ||
|   | 1cd1456d75 | ||
|   | b791a3eb10 | ||
|   | 3b22a8b170 | ||
|   | 419e8214ca | ||
|   | b9f8571f0f | ||
|   | c6d9a9d7f8 | ||
|   | 310aba6ccb | ||
|   | 9bd89ac4f6 | ||
|   | ea6a51dca9 | ||
|   | e701bcc50c | ||
|   | a1abf06e75 | ||
|   | 76ace394b0 | ||
|   | 4dac462f8f | ||
|   | 039672b1e7 | ||
|   | 1b26ecbbf5 | ||
|   | f4a7e96943 | ||
|   | a45bc2954f | ||
|   | 62f32467b7 | ||
|   | 600a1bf201 | ||
|   | 7e196e7aa6 | ||
|   | 9ad3507b66 | ||
|   | add1bdfcf6 | ||
|   | 7ea8a7c079 | ||
|   | 28e31f5165 | ||
|   | 10a6975c5d | ||
|   | b34ea87660 | ||
|   | 86ed69c50b | ||
|   | 02e824154c | ||
|   | dc973c8491 | ||
|   | 0a28e3a8d3 | ||
|   | 7a48c260e1 | ||
|   | c55c49a3a2 | ||
|   | 0fc9b06d12 | ||
|   | d71ad5a6bf | ||
|   | f0b3028306 | ||
|   | 752992c527 | ||
|   | 43c4476396 | ||
|   | f8172bed56 | ||
|   | c1f71b4cfc | ||
|   | 4799da15e7 | ||
|   | 4936e47c7a | ||
|   | cb965373aa | ||
|   | 654a91184a | ||
|   | 57997f7f4b | ||
|   | ca2f5be3d1 | ||
|   | 1b091073f1 | ||
|   | 85d2d3c442 | ||
|   | d77dfd63cf | ||
|   | db2bf52fca | ||
|   | 2c62d97440 | ||
|   | 53b2e64214 | ||
|   | ccf82a3ee5 | ||
|   | 9cb6f35e60 | ||
|   | da2e33a040 | ||
|   | f2d260bfa4 | ||
|   | 783c7244f9 | ||
|   | c9287e0e63 | ||
|   | 69b84d115c | ||
|   | 1745b898b1 | ||
|   | 5ba4c85249 | ||
|   | 03c87bb46d | ||
|   | dff5a76e9e | ||
|   | 50386f4ca4 | ||
|   | de6ba2ec80 | ||
|   | ce126015d9 | ||
|   | f2337c3d43 | ||
|   | 41b59d322a | ||
|   | dfea7c111e | ||
|   | 3d5d672297 | ||
|   | e4dcc6f342 | ||
|   | 9847249611 | ||
|   | 19742a54ec | ||
|   | 5af9ae7a80 | ||
|   | 78962a4a75 | ||
|   | 9a35d826aa | ||
|   | c9cdc89d35 | ||
|   | 33b75703ba | ||
|   | ca55aa3a24 | ||
|   | 95307c3902 | ||
|   | 89c8eae7e2 | ||
|   | 91614772dc | ||
|   | cd497ab4dc | ||
|   | f81895905e | ||
|   | d82fafaa7a | ||
|   | 0ea01acc46 | ||
|   | df55792a68 | ||
|   | 6a19c45269 | ||
|   | 23ee345441 | ||
|   | 0e8ff253f3 | ||
|   | 89bddb0bc4 | ||
|   | 77bbca9bb3 | ||
|   | 1acd4d8d58 | ||
|   | 4db72a712d | ||
|   | da2b7ba08e | ||
|   | f8b49411bf | ||
|   | a04b0d99b0 | ||
|   | 9e9735f617 | ||
|   | f906b36f01 | ||
|   | a9d1f4f854 | ||
|   | d017ae905f | ||
|   | bede280507 | ||
|   | ea130047bc | ||
|   | d77d8de63e | ||
|   | f5413d9202 | ||
|   | 559fc8f216 | ||
|   | 34b2df911d | ||
|   | 3d5a8a8cbd | ||
|   | 2b07097e14 | ||
|   | 372e943d8b | ||
|   | 95afcedc4f | ||
|   | c1dc8f017c | ||
|   | dbeddca263 | ||
|   | e65d133dec | ||
|   | b5e1dea1c2 | ||
|   | 3f19469939 | ||
|   | 87874b037a | ||
|   | adda6841d1 | ||
|   | a8092b921b | ||
|   | 930e4d69d1 | ||
|   | d9219df45b | ||
|   | a6d4ec28db | ||
|   | b29e13f777 | ||
|   | 9363b78ff6 | ||
|   | eba411fec7 | ||
|   | 9afe99e134 | ||
|   | 6678856178 | ||
|   | a1fea38c2c | ||
|   | 2d3265e66d | ||
|   | f6d4400db9 | ||
|   | 6d892a9266 | ||
|   | 356fa08da5 | ||
|   | 2225f8c890 | ||
|   | d1a89739f9 | ||
|   | 6ec6896763 | ||
|   | 9fb718d610 | ||
|   | c913b89a47 | ||
|   | 58b45693b7 | ||
|   | 29d3ece9b1 | ||
|   | 7e5db75230 | ||
|   | 283c0b9845 | ||
|   | 071a0f1651 | ||
|   | 1a116557a4 | ||
|   | 1468297626 | ||
|   | 87e94fdf52 | ||
|   | 64e15c33c8 | ||
|   | 7170f435d1 | ||
|   | 9942be0493 | ||
|   | eaad36277f | ||
|   | 37cc498568 | ||
|   | 8a3191340a | ||
|   | 0f4e998f0a | ||
|   | 0c93b649ba | ||
|   | 947d269877 | ||
|   | b4b9453948 | ||
|   | b99a4cd095 | ||
|   | a363d5aa46 | ||
|   | ae442dabb4 | ||
|   | 1477c88397 | ||
|   | 4172462938 | ||
|   | 27341ba4f8 | ||
|   | 7443076094 | ||
|   | a764bb4b1d | ||
|   | 57130e1af7 | ||
|   | 3f8a354c99 | ||
|   | 0b10d92929 | ||
|   | 1a1c55e661 | ||
|   | 87768f9e8b | ||
|   | d079f50364 | ||
|   | 72a89835c5 | ||
|   | 39d686810b | ||
|   | d936626001 | ||
|   | cdce1c5ea6 | ||
|   | d59530a54f | ||
|   | fe480811fb | ||
|   | 2e3e0d34c3 | ||
|   | 1e2984d0d9 | ||
|   | 3e9fe693c7 | ||
|   | 63161838d8 | ||
|   | 7c92951ae9 | ||
|   | 59a25854ef | ||
|   | 3ca5768974 | ||
|   | 9a2dce43dd | ||
|   | b7fce4317b | ||
|   | 97d9514b00 | ||
|   | 58f88708fa | ||
|   | d79c874aa5 | ||
|   | 58917c1ff8 | ||
|   | 13b171a62d | ||
|   | f0a601922a | ||
|   | d90090b35e | ||
|   | 094d1142e7 | ||
|   | eb09d1c925 | ||
|   | bd5d75361e | ||
|   | 5d7c0c635b | ||
|   | 606f538bf3 | ||
|   | 574c0eea27 | ||
|   | 4730cbc543 | ||
|   | 5c63359550 | ||
|   | ec3607f779 | ||
|   | 7efd0f8098 | ||
|   | 2a7c30a21a | ||
|   | 2639c3ee3f | ||
|   | 547e0153cb | ||
|   | 423664fcfa | ||
|   | c986c230ef | ||
|   | 7c6001f76e | ||
|   | d3620946ac | ||
|   | 479643221c | ||
|   | c9ef8bcf6a | ||
|   | d655a7c2f6 | ||
|   | 306861d3b4 | ||
|   | 7abab41eed | ||
|   | acc2691e33 | ||
|   | 21a65956b0 | ||
|   | 9738275ad1 | ||
|   | 7265034703 | ||
|   | 9bcc45591d | ||
|   | 38d657ba0e | ||
|   | 6a0d16c5bb | ||
|   | 490d4abb56 | ||
|   | a7d0f7fc99 | ||
|   | 0d2d3ff528 | ||
|   | 526169f0aa | ||
|   | 42940ff0e3 | ||
|   | e9b943363d | ||
|   | 01e98ff10c | ||
|   | d38981a17d | ||
|   | 7612e91691 | ||
|   | 76b0f20033 | ||
|   | b78c0f8a29 | ||
|   | ea93c7c8fc | ||
|   | 8ac1952974 | ||
|   | b4514a5bbf | ||
|   | 568053b06d | ||
|   | bb180bfc39 | ||
|   | 5ee635caed | ||
|   | 5dfd7c8597 | ||
|   | fe61b75d7e | ||
|   | e7bf565418 | ||
|   | 12071f6251 | ||
|   | 72ed2e3ed0 | ||
|   | d7c1f134fe | ||
|   | 5072d9f7ad | ||
|   | 5d42a1247a | ||
|   | ce64be22bd | ||
|   | 36f9386e8d | ||
|   | e9dc963805 | ||
|   | 8854322997 | ||
|   | 6018f1e8ca | ||
|   | 68f8ebb543 | ||
|   | 301f0218fd | ||
|   | a9c4a56893 | ||
|   | 3ea3d72f11 | ||
|   | 33da5bf4a7 | ||
|   | e3de01948a | ||
|   | 3cd92aaf54 | ||
|   | ab4e1996dd | ||
|   | b9ef082abf | ||
|   | dac7186da3 | ||
|   | 1fd6cc2b5e | ||
|   | 0b7da9790a | ||
|   | a9e0e0ead6 | ||
|   | 079754f1a9 | ||
|   | c45b5b1e86 | ||
|   | 2115cc685c | ||
|   | b99e56fc19 | ||
|   | 74c057eb84 | ||
|   | e8ececc0dc | ||
|   | ad120b7736 | ||
|   | 61c0711e79 | ||
|   | 81c3f6fce0 | ||
|   | 0a4416e633 | ||
|   | 6bb712854d | ||
|   | 46959e2407 | ||
|   | debbb049b0 | ||
|   | 375377fef9 | ||
|   | d5758dd6a3 | ||
|   | d5deffea58 | ||
|   | fadb43d9a1 | ||
|   | 044b641df0 | ||
|   | fbbacdb2ff | ||
|   | 4bfd7acd96 | ||
|   | ff03225cf4 | ||
|   | 8e820c0e47 | ||
|   | d718314324 | ||
|   | 1c653ec1b1 | ||
|   | fe16ddadce | ||
|   | 7a978054cc | ||
|   | 8ed3b5a747 | ||
|   | 6885150800 | ||
|   | 35d33a1c7d | ||
|   | 93a16bbd3c | ||
|   | d3cf6a4985 | ||
|   | 8ef7200c32 | ||
|   | e43da5ba86 | ||
|   | 10428b4340 | ||
|   | 43b7c05cd7 | ||
|   | 057f64b04c | ||
|   | 0971d783f3 | ||
|   | 54aabad3e8 | ||
|   | 606fbb5fec | ||
|   | 5093c27ba5 | ||
|   | 1d3661c946 | ||
|   | 304f7a068d | ||
|   | 7ea91be3fc | ||
|   | d15464b1ae | ||
|   | 150435f24e | ||
|   | e49507cd14 | ||
|   | ad3cc3ebb6 | ||
|   | ecaf53836d | ||
|   | 8fc36e7b24 | ||
|   | 1dbbac2aa3 | ||
|   | 4e5775fde4 | ||
|   | 9d81c7c366 | ||
|   | 2df0441f0f | ||
|   | 4216002ce5 | ||
|   | 1af6f4e151 | ||
|   | 05f284bc11 | ||
|   | 40c19b3ad4 | ||
|   | d1d972cca0 | ||
|   | 2a969921d6 | ||
|   | 4b3e1f5187 | ||
|   | 561963aa26 | ||
|   | 6c2c192836 | ||
|   | f0730f2295 | ||
|   | 9df91d2b63 | ||
|   | 09da1941fd | ||
|   | 613c8e4c28 | ||
|   | 7b407fd34d | ||
|   | fb7ff7a803 | ||
|   | 0c1f0e0522 | ||
|   | b5d771e9aa | ||
|   | 2f64255895 | ||
|   | 5b629a5c40 | ||
|   | b749cf52c3 | ||
|   | b9a36a9223 | ||
|   | 32debf6e6b | ||
|   | 06f6ae01c9 | ||
|   | db4d8ad802 | ||
|   | 9c82de9c9e | ||
|   | 8329835528 | ||
|   | 8e624aa31b | ||
|   | a2e8741517 | ||
|   | 3b7c107e8f | ||
|   | 558bc3f971 | ||
|   | 90a326f380 | ||
|   | 867dc1ae35 | ||
|   | 3f555464f7 | ||
|   | c0c0782258 | ||
|   | 377f57bcb6 | ||
|   | a51253f1e5 | ||
|   | e674e94da6 | ||
|   | 93a415f6d3 | ||
|   | 9364b97692 | ||
|   | 030915c9ea | ||
|   | 10882c309a | ||
|   | 8232fde160 | ||
|   | 45c3474d4d | ||
|   | c5a9e85343 | ||
|   | 8c7ef59583 | ||
|   | 36404b5c92 | ||
|   | 9949a117be | ||
|   | a3896db4f5 | ||
|   | f668062cab | ||
|   | bac0721078 | ||
|   | e29d7244d8 | ||
|   | 5a34b91a7a | ||
|   | eaac8b1428 | ||
|   | 6c6275dc88 | ||
|   | bd350ae679 | ||
|   | cadee28c68 | ||
|   | 3534828a99 | ||
|   | e1c5777e25 | ||
|   | 63553d4dd3 | ||
|   | 6033d779fc | ||
|   | 97db27e61f | ||
|   | 8ed861c05f | ||
|   | 4d416657bf | ||
|   | ede0399275 | ||
|   | 1a28ada04c | ||
|   | 8ac771cde4 | ||
|   | c6afbbfc73 | ||
|   | 5ba71e8109 | ||
|   | a0d2922aca | ||
|   | 446610b9df | ||
|   | 4905eea503 | ||
|   | 519fc128f6 | ||
|   | cc10955483 | ||
|   | e0bd47bb87 | ||
|   | fb0c3c4a06 | ||
|   | ceef1fdaf2 | ||
|   | e1ac287ed1 | ||
|   | 29cd3a5945 | ||
|   | cab082166b | ||
|   | 711dfd4da9 | ||
|   | 643948331d | ||
|   | 119030f1a5 | ||
|   | 3efee3dc52 | ||
|   | 70716d5121 | ||
|   | a7d11ead62 | ||
|   | 017830e433 | ||
|   | bceb175c75 | ||
|   | 98277c6b71 | ||
|   | b227fbe523 | ||
|   | ac6659a293 | ||
|   | 30a24ced1d | ||
|   | 3d1f4ae2ed | ||
|   | e86aff049c | ||
|   | 8ec0ba7c9e | ||
|   | c2898f0b2e | ||
|   | 0747374378 | ||
|   | a0c2fea833 | ||
|   | 811c1a445f | ||
|   | 72d3041e7e | ||
|   | 503180e7ec | ||
|   | 8ad548cad7 | ||
|   | 85d9acf605 | ||
|   | fc93c5ffcb | ||
|   | d6b0a9314c | ||
|   | 83bc07c3ff | ||
|   | 6ca680cd41 | ||
|   | 2b533dcb2b | ||
|   | 13a5a09f98 | ||
|   | 75ff7ebdbe | ||
|   | 6d8f3a1fc8 | ||
|   | a11b411912 | ||
|   | 2dba817c69 | ||
|   | d4df9a545f | ||
|   | cae21391e5 | ||
|   | 573b22d2c2 | ||
|   | 14d4112a9d | ||
|   | 28aa9db9c5 | ||
|   | d50c349e00 | ||
|   | 905362c59c | ||
|   | 97e7d44310 | ||
|   | bb71a1ef23 | ||
|   | de2771d008 | ||
|   | 02de34b65a | ||
|   | c6e14889f2 | ||
|   | f843732790 | ||
|   | 80e7ff0fc1 | ||
|   | 2964db6bdd | ||
|   | 5fbd94ec74 | ||
|   | 1d8d31d4f0 | ||
|   | 707c3eed99 | ||
|   | e33a81ad36 | ||
|   | 0f7d216379 | ||
|   | f0052e97a6 | ||
|   | 5c6076d48d | ||
|   | 883bd31249 | ||
|   | d7b5fde3c7 | ||
|   | f4273efef0 | ||
|   | 471dc966d9 | ||
|   | 50368654a4 | ||
|   | b1e1cc04ce | ||
|   | 554f67e295 | ||
|   | 278bd09a6c | ||
|   | 300d083038 | ||
|   | 34664f0025 | ||
|   | 7aaa803813 | ||
|   | b075b3ec1c | ||
|   | 0f3f4b0f5b | ||
|   | fd5ed78442 | ||
|   | d516e7dcb4 | ||
|   | 6a1f1ebf9d | ||
|   | 6ba5c02dd6 | ||
|   | c9b8f90859 | ||
|   | 70a0bf6d5c | ||
|   | 4caf8d6fab | ||
|   | aa90593158 | ||
|   | 9da5531483 | ||
|   | 9483459ba7 | ||
|   | ae57883770 | ||
|   | 8cb5a89d10 | ||
|   | 1a35fb0d4d | ||
|   | 1a2483c68c | ||
|   | 6c806238b2 | ||
|   | ea6e07a38b | ||
|   | ec6b07b275 | ||
|   | e85a03a1ca | ||
|   | 5d66b7677f | ||
|   | 3932834172 | ||
|   | d2e8294a1a | ||
|   | b06aa66ad8 | ||
|   | c45b48d949 | ||
|   | f779af1f65 | ||
|   | 78d039cd5f | ||
|   | fdbd5418c7 | ||
|   | 5df42466fd | ||
|   | ff2bed87f2 | ||
|   | 765e7d0b1e | ||
|   | 71ab6d42c8 | ||
|   | 2ea2a662ef | ||
|   | c2d45349a4 | ||
|   | 1b5cf410b7 | ||
|   | 3e79e2bed0 | ||
|   | 2a1f933702 | ||
|   | 251d3b487f | ||
|   | e55ec48c7d | ||
|   | 7ce2195adb | ||
|   | 537b79f1c2 | ||
|   | e4c4d22f56 | ||
|   | c4d244398c | ||
|   | 47260cdaf0 | ||
|   | 7ef13058c7 | ||
|   | 8066cb1804 | ||
|   | c5af6062fa | ||
|   | 908a2eba20 | ||
|   | 6f43957703 | ||
|   | 897ea28cf4 | ||
|   | d056ddbff1 | ||
|   | f157350059 | ||
|   | 7e3d99bda3 | ||
|   | c7c53e1d94 | ||
|   | b912ee3f6f | ||
|   | 06c05ad8e5 | ||
|   | 7f411400d5 | ||
|   | f24f234869 | ||
|   | 4e384e7811 | ||
|   | 5143448163 | ||
|   | 8e5e9f7cbc | ||
|   | 5ea7fd01bf | ||
|   | 8f3f6bc774 | ||
|   | 7f1524b42f | ||
|   | 4b7db4689d | ||
|   | 92831ecb43 | ||
|   | d486f3f306 | ||
|   | bfb7468f62 | ||
|   | 2e417d41db | ||
|   | b17f68cbfb | ||
|   | 8a22a523d6 | ||
|   | 97fe752a4e | ||
|   | cc4ea122a2 | ||
|   | db995d29e5 | ||
|   | c22dde8008 | ||
|   | 462d888894 | ||
|   | 9311b914ad | ||
|   | c5e0488210 | ||
|   | f548c27179 | ||
|   | 1f5f405b52 | ||
|   | cd923ab838 | ||
|   | aacdff92d2 | ||
|   | 32160d388a | ||
|   | 72e31929eb | ||
|   | 29014bb40e | ||
|   | e9d0a65536 | ||
|   | f7a3b68834 | ||
|   | dcc9d3b588 | ||
|   | b8f6f65943 | ||
|   | 3dacdda21a | ||
|   | 49b766120f | ||
|   | 2d7e1553f8 | ||
|   | d5d41213b0 | ||
|   | 328df00d2e | ||
|   | e4a5bf8234 | ||
|   | d6ee0f216c | ||
|   | 0246ef6b6a | ||
|   | 7fd40518fd | ||
|   | 95eb53edf6 | ||
|   | 4cdf2962cd | ||
|   | 5bf8ccd1fd | ||
|   | dd9fbbcfa7 | ||
|   | 72d8fd5be0 | ||
|   | b577229ed3 | ||
|   | 4ae870b799 | ||
|   | 0590e74b30 | ||
|   | b9956ba800 | ||
|   | fef6259d09 | ||
|   | e24f19e88b | ||
|   | cc6de1e71c | ||
|   | b0240a1c95 | ||
|   | 8acdec333b | ||
|   | eafcbb81f9 | ||
|   | 4b083463c8 | ||
|   | 78e834e04f | ||
|   | 2ed1893620 | ||
|   | 35f188a7dd | ||
|   | 07f577a9dd | ||
|   | 25c72b50c0 | ||
|   | e07346ebea | ||
|   | 699b466291 | ||
|   | f0f24ff96f | ||
|   | 1113997c71 | ||
|   | 487fb6e5c9 | ||
|   | 62908a323c | ||
|   | 021131271a | ||
|   | c20fa4dbd2 | ||
|   | b1826678da | ||
|   | 1630338f4e | ||
|   | 78af3d979c | ||
|   | 8346dfb1f5 | ||
|   | 5ecb4e4fe4 | ||
|   | ec9ff23b23 | ||
|   | 149e9931e7 | ||
|   | 58b62094bd | ||
|   | d357074ad4 | ||
|   | d9bacc129b | ||
|   | 28d869b099 | ||
|   | d04e87718a | ||
|   | 8d81bf60c9 | ||
|   | 4fe9094ff7 | ||
|   | 4cfde45755 | ||
|   | c28844dbeb | ||
|   | 837ea7c8d6 | ||
|   | 6c85ac8827 | ||
|   | c8eb8bf35d | ||
|   | 0f6cbddd57 | ||
|   | 530b4755bf | ||
|   | 679395b3fe | ||
|   | 9293442836 | ||
|   | 4841b412f3 | ||
|   | f03575ad89 | ||
|   | e0e5428ebd | ||
|   | 015f7edae2 | ||
|   | d5414f5d91 | ||
|   | 4bc3512d42 | ||
|   | 4c305994ca | ||
|   | 788e2cba04 | ||
|   | b79b79970e | ||
|   | 8b0f4de516 | ||
|   | a17000ad6d | ||
|   | c9f63c58df | ||
|   | c311b1c706 | ||
|   | 072451afae | ||
|   | 7349793463 | ||
|   | c0144eab86 | ||
|   | ba79b25944 | ||
|   | 3fb34b12a0 | ||
|   | b6c17e76c2 | ||
|   | 1201f20d79 | ||
|   | 98ae8e692e | ||
|   | 8342dbff4e | ||
|   | a22aa0f9a7 | ||
|   | b49d221ec1 | ||
|   | f1be315147 | ||
|   | 8aaac2a3d4 | ||
|   | bd07d30e47 | ||
|   | 54e103f00f | ||
|   | 5404d8f7ab | ||
|   | 1364e02c67 | ||
|   | b4818e2f9a | ||
|   | 734cf57d4a | ||
|   | 9236610ec1 | ||
|   | c33828a5d9 | ||
|   | faadb03e46 | ||
|   | 3a0c4c51d2 | ||
|   | 6c28c2b91e | ||
|   | 5226df6194 | ||
|   | 1ad23a3cbb | ||
|   | c4149ca304 | ||
|   | 68b02fe950 | ||
|   | d9408523a5 | ||
|   | 40ad0f063a | ||
|   | 40d85e8926 | ||
|   | e655f719e6 | ||
|   | ede0ea02c5 | ||
|   | e579575b21 | ||
|   | 06ffcc9fdf | ||
|   | 774d03e510 | ||
|   | adcac9dfe6 | ||
|   | 399e14c70c | ||
|   | ec8b51033b | ||
|   | ca5d167b6a | ||
|   | fcd1b001d1 | ||
|   | 1cabbefe04 | ||
|   | ecefe22c95 | ||
|   | 64db77b9a2 | ||
|   | 19d7360ad5 | ||
|   | 2f014cd827 | ||
|   | 7fb84205d9 | ||
|   | 47e1127c5f | ||
|   | e036b59306 | ||
|   | f4904c3b53 | ||
|   | 3002a63ba5 | ||
|   | b69717e6c3 | ||
|   | d07962953f | ||
|   | 857cf0d21e | ||
|   | 5f08c2615d | ||
|   | e87428ef33 | ||
|   | 03fd54fe70 | ||
|   | 086c2c8253 | ||
|   | 05c19a32ea | ||
|   | 99d174906a | ||
|   | 82e30a326a | ||
|   | 2963a9cdca | ||
|   | 288da75b2b | ||
|   | 0943a496dd | ||
|   | e5dd7cc2fa | ||
|   | 358836ef9f | ||
|   | aab4fac6c5 | ||
|   | 525540b603 | ||
|   | b30eeb4694 | ||
|   | 3faf0aa2fc | ||
|   | fd728dec5d | ||
|   | 08b14b72d4 | ||
|   | de2e005abf | ||
|   | 0fc75239a6 | ||
|   | 390fe30a0d | ||
|   | 633f49fcd2 | ||
|   | 30c0ba93b9 | ||
|   | e935fb9621 | ||
|   | 5ce8bb1d08 | ||
|   | 1acd12980a | ||
|   | 683235dd8a | ||
|   | 65fe183ad4 | ||
|   | f39d5d355c | ||
|   | eccc8e0ff0 | ||
|   | dd4d8e775c | ||
|   | 7a7f857b2f | ||
|   | 10882b7d93 | ||
|   | e669b81005 | ||
|   | 28a81d9539 | ||
|   | 6bf5e4a6b8 | ||
|   | a51eee93f4 | ||
|   | bece2555c2 | ||
|   | d98d405009 | ||
|   | 8d0881632c | ||
|   | e8b81da897 | ||
|   | acf4fbf750 | ||
|   | b4f1921d33 | ||
|   | 94b4816f53 | ||
|   | b6ddafde3e | ||
|   | b01036818f | ||
|   | ad7da1a0c3 | ||
|   | 1e0818d9d9 | ||
|   | a4686f01c3 | ||
|   | 84d76f9aab | ||
|   | b90bf5eb86 | ||
|   | fe258f3fe5 | ||
|   | d339494594 | ||
|   | adfaf13055 | ||
|   | 8abfeb5923 | ||
|   | c1a027a771 | ||
|   | 5f3094d79b | ||
|   | 925b81aca8 | ||
|   | c0c8437966 | ||
|   | 1d27b2fc4a | ||
|   | 5da43e7808 | ||
|   | 5edbb558ae | ||
|   | 7347cc1df2 | ||
|   | 20cac11b2a | ||
|   | 75c35c4ff8 | ||
|   | 9d573512d0 | ||
|   | 7921365853 | ||
|   | 43263fd3b9 | ||
|   | 59042a5ead | ||
|   | 91b14de807 | ||
|   | 81fab2be08 | ||
|   | 165b742782 | ||
|   | 76fef9c807 | ||
|   | e69ea0b9dc | ||
|   | 98d3183f2b | ||
|   | a29390a951 | ||
|   | 6291ce8617 | ||
|   | c76b1b50a0 | ||
|   | cc45e2aec0 | ||
|   | 17efebb8e8 | ||
|   | 5c94c733ee | ||
|   | 156b89dd9c | ||
|   | 34ba9f67e7 | ||
|   | 5ddaa6b872 | ||
|   | 9043fa7f56 | ||
|   | 4c8e487dc9 | ||
|   | d3b87179aa | ||
|   | 2166de8331 | ||
|   | f0bc3f001f | ||
|   | 50448e7085 | ||
|   | cd1d42353e | ||
|   | 5e588bf737 | ||
|   | 7ff777d178 | ||
|   | 861621189a | ||
|   | dcc00e08fd | ||
|   | a1b8a47d4b | ||
|   | 1fd6b5e239 | ||
|   | f91e45bf44 | ||
|   | 0675a45592 | ||
|   | 0c7c6ae451 | ||
|   | cf089e8c4c | ||
|   | 90928ac679 | ||
|   | 3bbcf71784 | ||
|   | 222734775d | ||
|   | f23ee7a6e0 | ||
|   | 5b075aa6d5 | ||
|   | 80cd6b693e | ||
|   | 04721a12b1 | ||
|   | 64e22c0e46 | ||
|   | d5a70c5b08 | ||
|   | eaac7b6bcf | ||
|   | b062a491cd | ||
|   | 1e868517bb | ||
|   | 7b2a93a2d7 | ||
|   | f57f0447c6 | ||
|   | 7126ff881e | ||
|   | e28da4b165 | ||
|   | 92d9b91f7c | ||
|   | 149c4a30c0 | ||
|   | 84e62062ec | ||
|   | dc1fb74850 | ||
|   | 00c6010789 | ||
|   | 5d35c058e0 | ||
|   | 1522a521f6 | ||
|   | 6e11b885f9 | ||
|   | 442ae6e0e8 | ||
|   | 6b49e83464 | ||
|   | f1ecf13fe1 | ||
|   | 83d1c8582b | ||
|   | 179f6cd454 | ||
|   | 91b1474ff0 | ||
|   | 15aabc88a1 | ||
|   | afc0d3017d | ||
|   | 9e0b1dc8aa | ||
|   | 55b482fd26 | ||
|   | 4f9c9a6566 | ||
|   | 4725120ee9 | ||
|   | a288f50fbb | ||
|   | 09cf2560a4 | ||
|   | 16353de7b1 | ||
|   | eb5834cb5c | ||
|   | 3ef5736aed | ||
|   | d2e7b77d16 | ||
|   | 8f794bce75 | ||
|   | c33196a50a | ||
|   | 6e8b5b431f | ||
|   | 8ca3ecf17f | ||
|   | 91f7db59ea | ||
|   | a0b4501352 | ||
|   | 345047820a | ||
|   | ac3525a953 | ||
|   | c8c3f5b134 | ||
|   | 51319c0718 | ||
|   | 43399b8b47 | ||
|   | a6596042b7 | ||
|   | 23ae85fc9c | ||
|   | 2da54862f1 | ||
|   | f272fb0559 | ||
|   | bd04e33586 | ||
|   | b09b9752ca | ||
|   | a810a48158 | ||
|   | b4f5792aa8 | ||
|   | fdf0330b4f | ||
|   | ca73743082 | ||
|   | df0cde2cfd | ||
|   | 5a8421e807 | ||
|   | 025ac95d81 | ||
|   | 71b5824fdc | ||
|   | 1a907c0be7 | ||
|   | 1635cabd32 | ||
|   | 27946a5b0f | ||
|   | e141822fd0 | ||
|   | 6326828a02 | ||
|   | 96b5362491 | ||
|   | 8ab91a51bc | ||
|   | 35e7e7af18 | ||
|   | 0e248a7302 | ||
|   | d5ce4d6600 | ||
|   | 2365bb5e87 | ||
|   | 2230216a7e | ||
|   | 54f896d25f | ||
|   | e47d239caf | ||
|   | ac259958d7 | ||
|   | 0505ad88a6 | ||
|   | b323de3383 | ||
|   | c0e023324b | ||
|   | 495806d5e3 | ||
|   | 3a9f745a2d | ||
|   | 7b15d114a3 | ||
|   | 6ac0f72169 | ||
|   | ff68030231 | ||
|   | d34361b6dd | ||
|   | 56c6ebe523 | ||
|   | 2c6d2e0eb4 | ||
|   | 8e64196a8f | ||
|   | 926d5faf21 | ||
|   | 18bad2af25 | ||
|   | 6be4dc4aac | ||
|   | 6398a59dda | ||
|   | 48158b1db6 | ||
|   | 47fe519e54 | ||
|   | 7e06f19bbc | ||
|   | 0b66c1f0d6 | ||
|   | ff2742ffd8 | ||
|   | 70c2992a5f | ||
|   | 4ac4ee6874 | ||
|   | 865164a404 | ||
|   | f9c8069ab2 | ||
|   | 2fbf5140e5 | ||
|   | 0126f8144a | ||
|   | 71383d7482 | ||
|   | 4d3bfc5f42 | ||
|   | c173d217de | ||
|   | d2da9a039f | ||
|   | c915edd458 | ||
|   | 504948452e | ||
|   | 3daa6c7a54 | ||
|   | 10cd1580a5 | ||
|   | 5b0876e106 | ||
|   | cfcdeaff01 | ||
|   | 7c34f233fd | ||
|   | 686146a7d9 | ||
|   | 44732d5977 | ||
|   | 05c3794cf7 | ||
|   | f0431a504a | ||
|   | eccec85ea6 | ||
|   | 16ff538804 | ||
|   | f81e07eb6f | ||
|   | 1cbd41ad87 | ||
|   | d8567b8427 | ||
|   | afe6a1923b | ||
|   | 0f60f4754f | ||
|   | 7e988d0401 | ||
|   | d85813c229 | ||
|   | 12eb56809d | ||
|   | d792172779 | ||
|   | 011562ae73 | ||
|   | 71c4e36933 | ||
|   | 6261982f6c | ||
|   | 4ac01e0ed0 | ||
|   | 2dfe07f13e | ||
|   | 7f4e4017ce | ||
|   | 635970f37b | ||
|   | 106e740220 | ||
|   | 3e6420ba6f | ||
|   | 79be8010d5 | ||
|   | 0b6e679f3b | ||
|   | 97c43ad2b9 | ||
|   | cbf978745c | ||
|   | 63dceada90 | ||
|   | 366aade8b4 | ||
|   | aeb505e3d9 | ||
|   | f9482e4773 | ||
|   | 57dfc22ff7 | ||
|   | adc489b6ed | ||
|   | 0623684315 | ||
|   | 68afccd859 | ||
|   | 99eef8fb28 | ||
|   | 47e7685d39 | ||
|   | b6ea596ade | ||
|   | 44d60b469b | ||
|   | 51087408df | ||
|   | 96226d9e6e | ||
|   | 28f0f62424 | ||
|   | 2e772a8cd4 | ||
|   | 3fd192f0cf | ||
|   | d16ae81961 | ||
|   | 211a8e093e | ||
|   | 84010a51d6 | ||
|   | e9700ea19b | ||
|   | e81ec68072 | ||
|   | 6096e97708 | ||
|   | 6f302b66b4 | ||
|   | b6e41890f7 | ||
|   | be5332a048 | ||
|   | 4d72aeb0cd | ||
|   | c7c3c35100 | ||
|   | 2f0df3c552 | ||
|   | e6effcd921 | ||
|   | cd462b9523 | ||
|   | 7e2e17d38b | ||
|   | 665d616a06 | ||
|   | ced90f5bb9 | ||
|   | ca0ddb6cb4 | ||
|   | 3d733813e1 | ||
|   | 45ddc0b154 | ||
|   | 87294497f3 | ||
|   | 5f45f9c0d0 | ||
|   | 7f78c06793 | ||
|   | 8ea5b7eebc | ||
|   | e49cd511af | ||
|   | 15c88646df | ||
|   | f47919543d | ||
|   | a95291d9cd | ||
|   | 033deb3d29 | ||
|   | 923994c1f4 | ||
|   | 3d45b839b4 | ||
|   | 55d1efa212 | ||
|   | 21d794a0e5 | ||
|   | 614022a78c | ||
|   | c00688e23a | ||
|   | 5c69917d19 | ||
|   | 6a5eb75b6c | ||
|   | 727c55eaa2 | ||
|   | 9b03173ec5 | ||
|   | ab95855d6d | ||
|   | bb84594c6b | ||
|   | 97392c76b1 | ||
|   | 53aec2b306 | ||
|   | a0a381dc63 | ||
|   | 4fa95edeec | ||
|   | b944f1d70e | ||
|   | 0f1a5d0085 | ||
|   | e7e10222e7 | ||
|   | 87c4fda588 | ||
|   | 0ff820de6f | ||
|   | 0dcf55e6d9 | ||
|   | a69842c910 | ||
|   | 318f635e4d | ||
|   | abf0d72316 | ||
|   | 5cd89c8844 | ||
|   | 501c1af38c | ||
|   | 8526e130d9 | ||
|   | 76fd08eade | ||
|   | bfe48ae9d2 | ||
|   | 8547cdba7c | ||
|   | 00d0cd631d | ||
|   | 04460d13cd | ||
|   | a17a15e5d7 | ||
|   | bfe2465658 | ||
|   | 4568987785 | ||
|   | c0e5a1419d | ||
|   | 23ac7ab748 | ||
|   | 5622dc74a8 | ||
|   | 528986f4f0 | ||
|   | e6b8ff3f91 | ||
|   | 3fc3c5296f | ||
|   | f4f2a14a31 | ||
|   | fa3f464cb6 | ||
|   | bed20538ae | ||
|   | 3da461c6e6 | ||
|   | 9c73e8452a | ||
|   | 750dab69d3 | ||
|   | 702d0da47c | ||
|   | 3a955b1e53 | ||
|   | d408bd93e8 | ||
|   | 63fd9eb1de | ||
|   | 4718ab6ddf | ||
|   | affd4b3a26 | ||
|   | 6a660dbcda | ||
|   | 5ff3af8b48 | ||
|   | 9d49070f93 | ||
|   | 5b3994a1dd | ||
|   | bb1e62c580 | ||
|   | 29cc776908 | ||
|   | d2ef60b2ec | ||
|   | 41ea496d41 | ||
|   | c69bb38929 | ||
|   | 23b3f8494e | ||
|   | 0ff94eec1b | ||
|   | f67a638565 | ||
|   | 778cf71c61 | ||
|   | e2da083b48 | ||
|   | dcc48c0d4b | ||
|   | 2446b4a591 | ||
|   | a973d633c8 | ||
|   | c3b11e6e0f | ||
|   | 44bec2d99e | ||
|   | 0d59d0a3f6 | ||
|   | ddc8372b09 | ||
|   | ea7325f4e0 | ||
|   | 6048f95415 | ||
|   | 5682705b8d | ||
|   | 6c3b82607d | ||
|   | 486c9f4ebf | ||
|   | 7c8adebf2d | ||
|   | ce98bb0dc1 | ||
|   | 60b49a4296 | ||
|   | 5d0a2ffae0 | ||
|   | bbcf7c722a | ||
|   | 66574eec6d | ||
|   | 305df3a42c | ||
|   | 323c6f4270 | ||
|   | c056b2b14c | ||
|   | 02ebb07fd8 | ||
|   | 59db0890c3 | ||
|   | 3ea0d9ed3a | ||
|   | 0371d11dd5 | ||
|   | 12f1ebaee9 | ||
|   | 5202cc22d1 | ||
|   | 07a34bdcbf | ||
|   | 27806da4be | ||
|   | a15dd1a3ce | ||
|   | 6cc7451c7c | ||
|   | 652aeee782 | ||
|   | 8e1e887b8f | ||
|   | 6601a2de64 | ||
|   | 75a42ffc32 | ||
|   | 8a80a52f5f | ||
|   | b373a434ba | ||
|   | cd78fdafe6 | ||
|   | 7a1b4c6db7 | ||
|   | f2c7664033 | ||
|   | 12b295f067 | ||
|   | 3ee46da40f | ||
|   | beadaa7212 | ||
|   | 16ef09426f | ||
|   | b8c1f1f5a9 | ||
|   | e027b5cbd6 | ||
|   | bf1bd73ad1 | ||
|   | 86fc95119a | ||
|   | b3a76ea17b | ||
|   | bababd9d53 | ||
|   | 8cd5180531 | ||
|   | f1ccbade8c | ||
|   | a66f4b0417 | ||
|   | ff495b2261 | ||
|   | 90e5824212 | ||
|   | 3d64021062 | ||
|   | fb8ed7428d | ||
|   | bdc273c10a | ||
|   | 2d96cffdc7 | ||
|   | 4356fccbcd | ||
|   | a169fd4ce7 | ||
|   | dcd418139e | ||
|   | 0cac2062d3 | ||
|   | 854c5d4ade | ||
|   | 0f96c6ec84 | ||
|   | b219bd66c1 | ||
|   | cb52f2c0b3 | ||
|   | d3273e03ef | ||
|   | afbfd963f3 | ||
|   | 2cd101c5f3 | ||
|   | b10bc24dee | ||
|   | 51a23df861 | ||
|   | 03a0a9dad9 | ||
|   | 362c0affbe | ||
|   | d5b523479f | ||
|   | 7719b8f6d7 | ||
|   | 3656c0d524 | ||
|   | 8b9e0dd6ea | ||
|   | b3921b1037 | ||
|   | d7d96e5dbf | ||
|   | 3934395b7b | ||
|   | 04fbe9a529 | ||
|   | badd6dd9a2 | ||
|   | 059082456d | ||
|   | 405b68e22f | ||
|   | c90bf6692c | ||
|   | b5ea5d0cc5 | ||
|   | 243617a1e1 | ||
|   | 9e703edd59 | ||
|   | d6c2cf2810 | ||
|   | ae7811acfa | ||
|   | e55731c099 | ||
|   | 9df5c74da4 | ||
|   | 8b75f9f785 | ||
|   | bf12428cf4 | ||
|   | b551df978b | ||
|   | c91d85d2f0 | ||
|   | 965237fa1f | ||
|   | 24cd9afc06 | ||
|   | 602fdefebd | ||
|   | 7e7818aa17 | ||
|   | 27a6023a6a | ||
|   | 3861879900 | ||
|   | 807eeb8351 | ||
|   | 045fa53d58 | ||
|   | 69d405ece7 | ||
|   | d3dc4d0c5b | ||
|   | 7beba1188e | ||
|   | 9779ebe12c | ||
|   | f72cfaa093 | ||
|   | cf8ccafb4a | ||
|   | 7fe281b0b8 | ||
|   | 5f70e9574f | ||
|   | 4be51923ba | ||
|   | a72c78f4a4 | ||
|   | b4d32a6de1 | ||
|   | 8a6b2d5daa | ||
|   | bebadeef14 | ||
|   | 3551be67f0 | ||
|   | 1103950b25 | ||
|   | 9d06e01cec | ||
|   | 24be946b7e | ||
|   | f56d2fc60f | ||
|   | 9f8356f409 | ||
|   | 8e6345d938 | ||
|   | 0eac78bd1c | ||
|   | 21db2502d0 | ||
|   | 38c3492123 | ||
|   | 6376bff476 | ||
|   | 38495a3ebc | ||
|   | cf00897be2 | ||
|   | da640f24ec | ||
|   | ed6a777c42 | ||
|   | 81af4485d3 | ||
|   | 94d8f0237d | ||
|   | c5e579dd38 | ||
|   | 7865e76ee2 | ||
|   | 4d37212cc0 | ||
|   | 9ca43f0bb4 | ||
|   | fe8d262175 | ||
|   | 493d6e7165 | ||
|   | 17b630bcd8 | ||
|   | 018c5ad3b4 | ||
|   | a14b4da977 | ||
|   | 01b4597cc7 | ||
|   | 0b083ccc1c | ||
|   | ca22cb0eae | ||
|   | bcbb8e5f8c | ||
|   | bea286cdd4 | ||
|   | 892d2ee8d2 | ||
|   | 7440608c14 | ||
|   | 6246f0295b | ||
|   | 53c39d9b43 | ||
|   | 9a50b60031 | ||
|   | fd74527320 | ||
|   | f91fb522ac | ||
|   | 7019c02b18 | ||
|   | 94f8422b9b | ||
|   | b25c01567a | ||
|   | b9329885de | ||
|   | ac88c4cff9 | ||
|   | 9674f2d238 | ||
|   | 38c9ecb6f1 | ||
|   | be9e9cdd5a | ||
|   | afdaf07446 | ||
|   | 5caaf10225 | ||
|   | daffc3a776 | ||
|   | 34c9748ce5 | ||
|   | f17acbf4d1 | ||
|   | 229f56ce2f | ||
|   | 0847bedc51 | ||
|   | 9e4546c305 | ||
|   | 97b01bf26a | ||
|   | e7011628d0 | ||
|   | 044ffdecbd | ||
|   | 1a06a3543b | ||
|   | 5fedc0bf1e | ||
|   | 7a881f867e | ||
|   | dfe73a6cfb | ||
|   | 45d0fb27ad | ||
|   | 31890af61d | ||
|   | a54b3ecc15 | ||
|   | c37cd1bd51 | ||
|   | 0e3ee89cbf | ||
|   | a049176c14 | ||
|   | 5ef2b0089e | ||
|   | 1cc4899593 | ||
|   | 26d1390be9 | ||
|   | dc65584fb3 | ||
|   | b3d5a708d5 | ||
|   | 904a5d296b | ||
|   | cc82e6a47a | ||
|   | a9d02ec854 | ||
|   | 6b5a2d3767 | ||
|   | 10d9060b94 | ||
|   | 8441839c01 | ||
|   | b669f5838f | ||
|   | 1a942f9ce1 | ||
|   | ae840758f7 | ||
|   | 082c08e5f9 | ||
|   | 74a43557ab | ||
|   | 184271789d | ||
|   | fa61b0cad8 | ||
|   | 7b197a90d1 | ||
|   | 62384af2f6 | ||
|   | b466202a1a | ||
|   | 7ab38c18d8 | ||
|   | 39841ee43e | ||
|   | e419800d98 | ||
|   | 63c99ab69a | ||
|   | e2a8fd2279 | ||
|   | bbde520471 | ||
|   | 45fb12f98e | ||
|   | 4be3dcce50 | ||
|   | d12a41c769 | ||
|   | ed9a58c9ed | ||
|   | 4389cea5a1 | ||
|   | d24854920b | ||
|   | 9902443bee | ||
|   | 8040b2ef16 | ||
|   | 4533680b10 | ||
|   | 3b28175135 | ||
|   | 8e22812265 | ||
|   | 409bc91b9e | ||
|   | 61fe543a2a | ||
|   | 8a949a7e64 | ||
|   | b0dc9fb97a | ||
|   | 83114d1002 | ||
|   | 94a25a903f | ||
|   | 4f402f9e55 | ||
|   | 27bb2e3dcc | ||
|   | 66cc52f6ec | ||
|   | ed1367b116 | ||
|   | 5c055352e4 | ||
|   | 8dcff5ada1 | ||
|   | 4b8b23d7d5 | ||
|   | e576f6aed3 | ||
|   | 97ab04da91 | ||
|   | c6361bb36e | ||
|   | b0b3dc225d | ||
|   | 9cbaba192a | ||
|   | f511598e13 | ||
|   | 5ffff3b7aa | ||
|   | 24c4fa1c4f | ||
|   | 7f312c1273 | ||
|   | ef5c226c81 | ||
|   | 3f029cf799 | ||
|   | 5bf64a8bec | ||
|   | 89f9c537f8 | ||
|   | e8d7f57818 | ||
|   | 9b42fa78e7 | ||
|   | 96d98e8f39 | ||
|   | 1f3a281e78 | ||
|   | dab4b66ee0 | ||
|   | 64dd192ddb | ||
|   | b0a5c383d0 | ||
|   | 4836cc99eb | ||
|   | ba33873354 | ||
|   | 12c838cab0 | ||
|   | a83a1c83a7 | ||
|   | 2234f47170 | ||
|   | 4bae1b17fc | ||
|   | 6a7a0e0fa6 | ||
|   | bff987c55f | ||
|   | e467006913 | ||
|   | 1d646d4a6d | ||
|   | 70bd4936a1 | ||
|   | 5ae7add6d2 | ||
|   | 02b206ce7c | ||
|   | 2ea626a567 | ||
|   | 653909ec11 | ||
|   | 1d7c148eaf | ||
|   | 94a7e130ca | ||
|   | 609abacdf0 | ||
|   | 033ff2e49a | ||
|   | 00a9bf0641 | ||
|   | 100f322456 | ||
|   | 2251e08d30 | ||
|   | 14e9beef53 | ||
|   | c7cce23d54 | ||
|   | 7becf32352 | ||
|   | 741eda9f4e | ||
|   | 473f51481c | ||
|   | 684f9bd11b | ||
|   | b4b7f0c360 | ||
|   | cf42d02628 | ||
|   | cc9a9eab7b | ||
|   | 784d6abc9b | ||
|   | 0eafc07184 | ||
|   | 7e9499bd2e | ||
|   | d01a52aa95 | ||
|   | 6bcd492980 | ||
|   | 96b15da04b | ||
|   | e0f1801693 | ||
|   | d195ad85c5 | ||
|   | 773f7b6c1b | ||
|   | 40f29fe399 | ||
|   | b19eb117c1 | ||
|   | f930ba5eff | ||
|   | fbbda6c230 | ||
|   | 47db4968e5 | ||
|   | 1aff2e518c | ||
|   | 24134ca49e | ||
|   | aadbe05a5e | ||
|   | 18eddf4700 | ||
|   | 0869ba7e70 | ||
|   | cba5db1c53 | ||
|   | 0aa5430e23 | ||
|   | 88a91828cb | ||
|   | 27af89f5fe | ||
|   | 6f6d483bfe | ||
|   | 915072c191 | ||
|   | 76077b92ae | ||
|   | f0d1a527a5 | ||
|   | fdb2a96d1c | ||
|   | 849e3ac187 | ||
|   | 5c4cf21c59 | ||
|   | 40ee3e5d9b | ||
|   | 77a7cc034e | ||
|   | 82b7881765 | ||
|   | 3515775267 | ||
|   | 10e12aa1c1 | ||
|   | 7fb4e62aa3 | ||
|   | 2605eaa614 | ||
|   | 8e97b4820d | ||
|   | 89af4cdb68 | ||
|   | 6099c1a25a | ||
|   | fd23758aea | ||
|   | 8ad0b89db1 | ||
|   | e7dffa3ff4 | ||
|   | 2772b5d2e2 | ||
|   | df6d9b5f70 | ||
|   | c9622d6d57 | ||
|   | 1f0b7c3c7e | ||
|   | c12245037e | ||
|   | fe6d2a50a5 | ||
|   | 7be84950f8 | ||
|   | ba212da222 | ||
|   | 122b833256 | ||
|   | 7c73479041 | ||
|   | 151f2e99ae | ||
|   | da367e813f | ||
|   | 9143dfe336 | ||
|   | 29914d6a72 | ||
|   | 0dbef72a97 | ||
|   | 3bb118bfe1 | ||
|   | 85ce3be077 | ||
|   | 064c2bf0a8 | ||
|   | c96d06ccc5 | ||
|   | a658dbb753 | ||
|   | bf5d5b629e | ||
|   | 241d576519 | ||
|   | 7807e9bdd0 | ||
|   | fcbf15fed6 | ||
|   | cd90a11209 | ||
|   | ff65707ea2 | ||
|   | b16026070c | ||
|   | 1b5fbf86d8 | ||
|   | 5eb1be8101 | ||
|   | 6a863cd26a | ||
|   | 87ebb7b6c7 | ||
|   | 1233a74307 | ||
|   | 221890acfb | ||
|   | 687c7e766e | ||
|   | ba22c407d3 | ||
|   | a8b9ed56b5 | ||
|   | 3004869e19 | ||
|   | 1145853fe1 | ||
|   | f1617a25b1 | ||
|   | 932be558d9 | ||
|   | ee3a37d3b9 | ||
|   | 5ac412a582 | ||
|   | 1625290bc3 | ||
|   | 1ec169ad49 | ||
|   | 53be552e44 | ||
|   | d3a75d46b9 | ||
|   | 256512c961 | ||
|   | 5c12ac5bcc | ||
|   | 02a2bcb113 | ||
|   | 1f0a01c725 | ||
|   | 6ea164ede1 | ||
|   | 65bae85ecc | ||
|   | 2fd7dcf4d0 | ||
|   | aa3bbbe038 | ||
|   | 6cb09a6f95 | ||
|   | 45868f05d3 | ||
|   | aac7401e20 | ||
|   | c2fc290edd | ||
|   | 330357fc36 | ||
|   | f4a3d6a64e | ||
|   | 2e0963ec81 | ||
|   | 897cb6e62a | ||
|   | 80868bd48e | ||
|   | b3df78c56f | ||
|   | 783a4259e3 | ||
|   | fcf19b8dc8 | ||
|   | 1f9f89817d | ||
|   | 7b94da7d85 | ||
|   | 164406f6c2 | ||
|   | 90ef2adc6b | ||
|   | d65f10f88b | ||
|   | dca0ece9e0 | ||
|   | baabc155c8 | ||
|   | 7eb94412d6 | ||
|   | 0fc8b24f85 | ||
|   | 88f6ef5b96 | ||
|   | 7442483419 | ||
|   | 9c61933c04 | ||
|   | 2b36a99720 | ||
|   | c2cfc42ba4 | ||
|   | 4f32704e08 | ||
|   | fccf43685f | ||
|   | 39135d81ad | ||
|   | ff4b10681e | ||
|   | 10b7908fc2 | ||
|   | 31790da8c6 | ||
|   | 4621201c47 | ||
|   | 692ac31dbf | ||
|   | ed1d163d55 | ||
|   | e931c9040c | ||
|   | f23cb48ea4 | ||
|   | c3b2b6b07b | ||
|   | f89bf590ba | ||
|   | fea17dc00b | ||
|   | dbb1069920 | ||
|   | afc4ccfaa9 | ||
|   | 38d55a1c07 | ||
|   | 5fca29f103 | ||
|   | 78f34b2ca4 | ||
|   | 8e8028e809 | ||
|   | 8dc70687f8 | ||
|   | fa22f9ee64 | ||
|   | b33c0d3f81 | ||
|   | 339009add4 | ||
|   | 798c823c4b | ||
|   | 14ad86f2a3 | ||
|   | a3a714dc17 | ||
|   | e8d8b0d41d | ||
|   | 17daad8f89 | ||
|   | e178263b3b | ||
|   | 4febbc261e | ||
|   | ef3a6942fd | ||
|   | f8ac2be62b | ||
|   | 25447c34e5 | ||
|   | 37cdf8fd48 | ||
|   | ac8e7dc959 | ||
|   | 8293382840 | ||
|   | d85a3e7743 | ||
|   | f3f5ffb5c8 | ||
|   | 99e6702c62 | ||
|   | e143c25078 | ||
|   | 3fb67972be | ||
|   | 61c04d4e09 | ||
|   | b22f728958 | ||
|   | 112be7e383 | ||
|   | 6a7f83fed5 | ||
|   | 4b9698a735 | ||
|   | ec3d203a6d | ||
|   | e77b8f5475 | ||
|   | da8bbd321f | ||
|   | 98fd011def | ||
|   | 9dccbc5316 | ||
|   | 03fa26daf9 | ||
|   | fbc41e3895 | ||
|   | f1a6d0c02c | ||
|   | 67f6bb7155 | ||
|   | 86282f596c | ||
|   | e0f24c795c | ||
|   | 7d44ed860c | ||
|   | 091094a24c | ||
|   | ba18ee518c | ||
|   | 513a031691 | ||
|   | cc79de1106 | ||
|   | bd90e8efb2 | ||
|   | 4bd88ff11d | ||
|   | d27ee61292 | ||
|   | 0c20b3345f | ||
|   | 0f3c8c7193 | ||
|   | 16761ec605 | ||
|   | 1069440cda | ||
|   | 60f5702f17 | ||
|   | ee70133e47 | ||
|   | 06a9fdeb2e | ||
|   | f14bd62004 | ||
|   | 67cbaf22b7 | ||
|   | 60b166dba2 | ||
|   | 66e1647ede | ||
|   | a1a35c00a5 | ||
|   | b02e3361c4 | ||
|   | 2b9ceaa25a | ||
|   | 109b5a9755 | ||
|   | cc4df86c10 | ||
|   | e93532c395 | ||
|   | 6ff688326a | ||
|   | eda5d2872f | ||
|   | dc88394f5f | ||
|   | ec85c9a2c6 | ||
|   | 1341638556 | ||
|   | 4875dfee11 | ||
|   | d834ba8bd4 | ||
|   | 6191067771 | ||
|   | 6c3a571163 | ||
|   | 5efb07e10e | ||
|   | b25ec18ce6 | ||
|   | f3cd281241 | ||
|   | 58b93cbf4c | ||
|   | 57fc0349ff | ||
|   | d0a2cea772 | ||
|   | 58d5801fb5 | ||
|   | e5f2e59798 | ||
|   | 1166921057 | ||
|   | aeb49576f2 | ||
|   | 7ef1fecef8 | ||
|   | fd630373b5 | ||
|   | d365d8f170 | ||
|   | dfa5e1172f | ||
|   | daf195898a | ||
|   | c61c0a39cf | ||
|   | 6137e6baa5 | ||
|   | fd16fd9ffe | ||
|   | 2b8bd5f2cc | ||
|   | d312c2e9e7 | ||
|   | 578b0d2268 | ||
|   | ffb41b0109 | ||
|   | c63fb5d796 | ||
|   | 8caee732e8 | ||
|   | df5381adce | ||
|   | f34836b7fa | ||
|   | 44b459883a | ||
|   | 14a8592ae3 | ||
|   | 787d0dce4a | ||
|   | 8be05ff93d | ||
|   | 3014af565c | ||
|   | 315252bdc4 | ||
|   | c36c3b4607 | ||
|   | 7d5e939bab | ||
|   | f75c9d1eed | ||
|   | 38cb9855ea | ||
|   | ed8b56d624 | ||
|   | bca48b13ae | ||
|   | 29426edb05 | ||
|   | 33a2dc687f | ||
|   | e2398a21b2 | ||
|   | f19530276e | ||
|   | 2b9b92a78c | ||
|   | 99c55dac10 | ||
|   | 25667e46f9 | ||
|   | 2f4e8f2399 | ||
|   | 9169183769 | ||
|   | c420f50831 | ||
|   | c6c9279ef4 | ||
|   | c125e2991d | ||
|   | 5348b19d6a | ||
|   | afd426daac | ||
|   | 202c511cfa | ||
|   | 651eb295a4 | ||
|   | d798aaed33 | ||
|   | 63ef347cc9 | ||
|   | 3139b2d5a0 | ||
|   | 2c80bbb244 | ||
|   | af06755ada | ||
|   | 97d6dbaa6c | ||
|   | 74cf82a1c7 | ||
|   | 74634889ab | ||
|   | dbe30fcd77 | ||
|   | 24a7f3a320 | ||
|   | d3650f1145 | ||
|   | 4801db9050 | ||
|   | 6445281658 | ||
|   | 87719f5938 | ||
|   | 5ba1ec433b | ||
|   | 7c5b382458 | ||
|   | 8960426128 | ||
|   | e1d47d5a92 | ||
|   | 9407c272aa | ||
|   | bccbd7b400 | ||
|   | a24dc010ec | ||
|   | c5e5d50fb8 | ||
|   | be1c520320 | ||
|   | 3d18d0f893 | ||
|   | c3351a38a6 | ||
|   | 0b86340a8d | ||
|   | 829371b032 | ||
|   | b342207bc7 | ||
|   | 58f4fdced3 | ||
|   | 253844cbcf | ||
|   | e2e2b9ffb4 | ||
|   | 2568042f5f | ||
|   | 722edf4b9a | ||
|   | e406d364e4 | ||
|   | 31c37f41b2 | ||
|   | 6cd879bbc5 | ||
|   | b7974050fe | ||
|   | e9c9d0816e | ||
|   | a437692e1a | ||
|   | 2a14d2f3c8 | ||
|   | 559e2d1889 | ||
|   | a1aa919f80 | ||
|   | cbccb27a5a | ||
|   | bbad36d576 | ||
|   | df6c9d55b5 | ||
|   | 36a1d9c364 | ||
|   | 1f3681d5ac | ||
|   | 0159f8e53f | ||
|   | 0432be64fc | ||
|   | 481e062961 | ||
|   | 72b8abdeb6 | ||
|   | 7ec3ee41d1 | ||
|   | b765fa4769 | ||
|   | 06685b162e | ||
|   | 7bcad7c424 | ||
|   | 6e054b3cc6 | ||
|   | e643f6b0f8 | ||
|   | e44c0f85c2 | ||
|   | ea66e968eb | ||
|   | f7e73d804e | ||
|   | 2ff4df56a1 | ||
|   | 346c45fe0c | ||
|   | f98b42a36e | ||
|   | f77a0a266c | ||
|   | 0be672788f | ||
|   | e2e3d11d42 | ||
|   | bb127bb567 | ||
|   | 8eb4f89db8 | ||
|   | 4a87ea3e70 | ||
|   | 61115fce99 | ||
|   | 4f31120394 | ||
|   | b085cd65ce | ||
|   | f76ec0721a | ||
|   | ef3944fbbf | ||
|   | b158fbc0d8 | ||
|   | 68f2d66e97 | ||
|   | 0cdd1735bd | ||
|   | 70f5ead20b | ||
|   | 574e5616f8 | ||
|   | 94fa810590 | ||
|   | 37f69da701 | ||
|   | f2f8448ade | ||
|   | b357d3fff2 | ||
|   | b417194905 | ||
|   | d8741da20a | ||
|   | c469be9a62 | ||
|   | ff4eb339ef | ||
|   | 78489383c0 | ||
|   | f67c1b415f | ||
|   | 570c16d921 | ||
|   | c8bc60568a | ||
|   | 73de3ba856 | ||
|   | 6a69be8537 | ||
|   | 3ee381d505 | ||
|   | 7ce744e2e4 | ||
|   | b81d21c991 | ||
|   | e9fe0992c6 | ||
|   | d5ef9018fa | ||
|   | c2737a7c51 | ||
|   | 4b6d8733c6 | ||
|   | f22a3e0955 | ||
|   | 4b8144a2f7 | ||
|   | abac52e23c | ||
|   | 9aa089313e | ||
|   | b18f2c481a | ||
|   | ec83b9f77b | ||
|   | fad5495e02 | ||
|   | 70dec1171e | ||
|   | 0673a6fce3 | ||
|   | 8f525b1407 | ||
|   | e83a991a4b | ||
|   | c000432a52 | ||
|   | c06d2d6927 | ||
|   | aa29653a8f | ||
|   | 3f7e4ad486 | ||
|   | 0eab546b2f | ||
|   | 8830d216d1 | ||
|   | 9fa1e3d449 | ||
|   | fe5dce7159 | ||
|   | 952fa31548 | ||
|   | cc058ccc61 | ||
|   | bc26ed9701 | ||
|   | 26135fc1a0 | ||
|   | 0bd14672ff | ||
|   | 7c7150cde8 | ||
|   | b08282b0c1 | ||
|   | 3bf6e1befc | ||
|   | 52692371ac | ||
|   | 159ac1d8bb | ||
|   | 7f1ffdbc79 | ||
|   | 5fe64931dc | ||
|   | ee67855b48 | ||
|   | 594a97f43f | ||
|   | 7fb435a8b4 | ||
|   | 01e74d6116 | ||
|   | b321d75b39 | ||
|   | 1e47a45723 | ||
|   | 88c609e5ef | ||
|   | 775d1a424e | 
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -362,5 +362,8 @@ MigrationBackup/ | ||||
| # Fody - auto-generated XML schema | ||||
| FodyWeavers.xsd | ||||
|  | ||||
|  | ||||
| /framework/*Pro* | ||||
| /src/*Pro*/ | ||||
| /src/*Pro* | ||||
| /src/*pro* | ||||
| /src/*pro*/ | ||||
| /src/ThingsGateway.Server/Configuration/GiteeOAuthSettings.json | ||||
|   | ||||
							
								
								
									
										202
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Cachetribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright 2023-present Diego | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
							
								
								
									
										202
									
								
								LICENSE.txt
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								LICENSE.txt
									
									
									
									
									
								
							| @@ -1,202 +0,0 @@ | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright 2023-present Diego | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
							
								
								
									
										103
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,38 +1,101 @@ | ||||
|  | ||||
| # ThingsGateway | ||||
|  | ||||
| ## 介绍 | ||||
|  | ||||
|  | ||||
|  **NetCore** 跨平台边缘采集网关(工业设备采集) | ||||
| ## Introduction | ||||
|  | ||||
|  **ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22) | ||||
|  | ||||
| A cross-platform, high-performance edge data collection gateway based on net9. | ||||
|  | ||||
|  | ||||
|  **ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 **ThingsGateway - Admin** | ||||
| ## Documentation | ||||
|  | ||||
|  | ||||
| [Documentation](https://thingsgateway.cn/). | ||||
|  | ||||
| [NuGet](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22) | ||||
|  | ||||
|  | ||||
|  | ||||
| ## 文档 | ||||
| ## Demo | ||||
|  | ||||
| [ThingsGateway](https://diego2098.gitee.io/thingsgateway-docs/) 文档。 | ||||
|  | ||||
| [Demo](https://demo.thingsgateway.cn/) | ||||
|  | ||||
| ## 协议 | ||||
|  | ||||
| Account: **SuperAdmin** | ||||
|  | ||||
| [ThingsGateway](https://gitee.com/diego2098/ThingsGateway) 采用 [Apache-2.0](https://gitee.com/diego2098/ThingsGateway/blob/master/LICENSE.zh) 开源协议。 | ||||
|  | ||||
| Password: **111111** | ||||
|  | ||||
| ## 演示 | ||||
|  | ||||
| **In the upper-right corner, switch to the IoT Gateway module in the personal popup box** | ||||
|  | ||||
| [ThingsGateway演示地址](http://120.24.62.140:5000/) | ||||
| ## Docker | ||||
|  | ||||
| 账户	:  **superAdmin**	 | ||||
| ```shell | ||||
|  | ||||
| 密码 : **111111** | ||||
| docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway | ||||
|  | ||||
| ## 赞助 | ||||
|  | ||||
| [ThingsGateway赞助途径](https://diego2098.gitee.io/thingsgateway-docs/docs/donate) | ||||
|  | ||||
| ## 社区 | ||||
|  | ||||
| QQ群:605534569 | ||||
| docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64 | ||||
| ``` | ||||
|  | ||||
|  | ||||
|  | ||||
| ### Plugin List | ||||
|  | ||||
|  | ||||
|  | ||||
| #### Data Collection Plugins | ||||
|  | ||||
|  | ||||
| | Plugin Name | Remarks                                                       | | ||||
| | ----------- | ------------------------------------------------------------- | | ||||
| | Modbus      | Supports Rtu/Tcp message formats, with Serial/Tcp/Udp links   | | ||||
| | SiemensS7   | Siemens PLC S7 series                                         | | ||||
| | Dlt6452007  | Supports Serial/Tcp/Udp links                                 | | ||||
| | OpcDaMaster | Compiled for 64-bit                                           | | ||||
| | OpcUaMaster | Supports certificate login, object extension, Json read/write | | ||||
| | Webhook          | Webhook                                             | | ||||
|  | ||||
| #### Business Plugins | ||||
|  | ||||
|  | ||||
| | Plugin Name      | Remarks                                                                                           | | ||||
| | ---------------- | ------------------------------------------------------------------------------------------------- | | ||||
| | ModbusSlave      | Supports Rtu/Tcp message formats, with Serial/Tcp/Udp links, supports Rpc reverse writing         | | ||||
| | OpcUaServer      | OpcUa server, supports Rpc reverse writing                                                        | | ||||
| | MqttClient       | Mqtt client, supports Rpc reverse writing, script-customizable upload content                     | | ||||
| | MqttServer       | Mqtt server, supports WebSocket, supports Rpc reverse writing, script-customizable upload content | | ||||
| | KafkaProducer    | Script-customizable upload content                                                                | | ||||
| | RabbitMQProducer | Script-customizable upload content                                                                | | ||||
| | SqlDB            | Relational database storage, supports historical storage and real-time data updates               | | ||||
| | SqlHistoryAlarm      | Alarm historical data relational database storage                                                 | | ||||
| | TDengineDB       | Time-series database storage                                                                      | | ||||
| | QuestDB          | Time-series database storage                                                                      | | ||||
|  | ||||
|  | ||||
|  | ||||
| ## License | ||||
|  | ||||
|  | ||||
| [License](https://thingsgateway.cn/docs/1) | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Sponsorship | ||||
|  | ||||
|  | ||||
| [Sponsorship Approach](https://thingsgateway.cn/docs/1000) | ||||
|  | ||||
|  | ||||
| ## Community | ||||
|  | ||||
|  | ||||
| QQ Group: 605534569 [Jump](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NnBjPO-8kcNFzo_RzSbdICflb97u2O1i&authKey=V1MI3iJtpDMHc08myszP262kDykbx2Yev6ebE4Me0elTe0P0IFAmtU5l7Sy5w0jx&noverify=0&group_code=605534569) | ||||
|  | ||||
|  | ||||
| ## Pro Plugins | ||||
|  | ||||
|  | ||||
| [Plugin List](https://thingsgateway.cn/docs/1001) | ||||
|   | ||||
							
								
								
									
										86
									
								
								README.zh-CN.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								README.zh-CN.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| # ThingsGateway | ||||
|  | ||||
| ## 介绍 | ||||
|  | ||||
| 基于net9的跨平台高性能边缘采集网关 | ||||
|  | ||||
| ## 文档 | ||||
|  | ||||
| [文档](https://thingsgateway.cn/) | ||||
|  | ||||
| [NuGet](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22) | ||||
|  | ||||
|  | ||||
| ## 演示 | ||||
|  | ||||
| [ThingsGateway演示地址](https://demo.thingsgateway.cn/) | ||||
|  | ||||
| 账户	:  **SuperAdmin** | ||||
|  | ||||
| 密码 : **111111** | ||||
|  | ||||
| **右上角个人弹出框中,切换到物联网关模块** | ||||
|  | ||||
| ## Docker | ||||
|  | ||||
| ```shell | ||||
|  | ||||
| docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway | ||||
|  | ||||
| docker pull registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64 | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ### 插件列表 | ||||
|  | ||||
| #### 采集插件 | ||||
|  | ||||
|  | ||||
| | 插件名称    | 备注                                  | | ||||
| | ----------- | ------------------------------------- | | ||||
| | Modbus      | Rtu/Tcp报文格式,支持串口/Tcp/Udp链路 | | ||||
| | SiemensS7   | 西门子PLC S7系列                      | | ||||
| | Dlt6452007  | 支持串口/Tcp/Udp链路                  | | ||||
| | OpcDaMaster | 64位编译                              | | ||||
| | OpcUaMaster | 支持证书登录,扩展对象,Json读写      | | ||||
|  | ||||
| #### 业务插件 | ||||
|  | ||||
|  | ||||
| | 插件名称         | 备注                                                       | | ||||
| | ---------------- | ---------------------------------------------------------- | | ||||
| | ModbusSlave      | Rtu/Tcp报文格式,支持串口/Tcp/Udp链路,支持Rpc反写         | | ||||
| | OpcUaServer      | OpcUa服务端,支持Rpc反写                                   | | ||||
| | MqttClient       | Mqtt客户端,支持Rpc反写,脚本自定义上传内容                | | ||||
| | MqttServer       | Mqtt服务端,支持WebSocket,支持Rpc反写,脚本自定义上传内容 | | ||||
| | KafkaProducer    | 脚本自定义上传内容                                         | | ||||
| | RabbitMQProducer | 脚本自定义上传内容                                         | | ||||
| | SqlDB            | 关系数据库存储,支持历史存储和实时数据更新                 | | ||||
| | SqlHistoryAlarm      | 报警历史数据关系数据库存储                                 | | ||||
| | TDengineDB       | 时序数据库存储                                             | | ||||
| | QuestDB          | 时序数据库存储                                             | | ||||
| | Webhook          | Webhook                                             | | ||||
|  | ||||
| ## 协议 | ||||
|  | ||||
| [版权声明](https://thingsgateway.cn/docs/1) | ||||
|  | ||||
|  | ||||
| ## 赞助 | ||||
|  | ||||
| [赞助途径](https://thingsgateway.cn/docs/1000) | ||||
|  | ||||
| ## 社区 | ||||
|  | ||||
| QQ群:605534569 [跳转](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NnBjPO-8kcNFzo_RzSbdICflb97u2O1i&authKey=V1MI3iJtpDMHc08myszP262kDykbx2Yev6ebE4Me0elTe0P0IFAmtU5l7Sy5w0jx&noverify=0&group_code=605534569) | ||||
|  | ||||
| ## Pro插件 | ||||
|  | ||||
| [插件列表](https://thingsgateway.cn/docs/1001) | ||||
|  | ||||
|  | ||||
| ## 特别声明 | ||||
|  | ||||
| ThingsGateway 项目已加入 [dotNET China](https://gitee.com/dotnetchina)  组织。<br/> | ||||
|  | ||||
|  | ||||
| @@ -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,15 +0,0 @@ | ||||
| <Project> | ||||
| 	<PropertyGroup> | ||||
| 		<Version>3.0.0.5</Version> | ||||
| 		<LangVersion>latest</LangVersion> | ||||
| 		<TargetFrameworks>net6.0;net7.0</TargetFrameworks> | ||||
| 		<Authors>Diego</Authors> | ||||
| 		<Product>ThingsGateway</Product> | ||||
| 		<Copyright>© 2023-present Diego</Copyright> | ||||
| 		<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl> | ||||
| 		<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages> | ||||
| 		<GenerateDocumentationFile>False</GenerateDocumentationFile> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
|  | ||||
| </Project> | ||||
| @@ -1,16 +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 System; | ||||
|  | ||||
| global using ThingsGateway.Components; | ||||
|  | ||||
| @@ -1,38 +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 Photino.Blazor; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Demo; | ||||
|  | ||||
| internal class Program | ||||
| { | ||||
|     [STAThread] | ||||
|     private static void Main(string[] args) | ||||
|     { | ||||
|         System.IO.Directory.SetCurrentDirectory(AppContext.BaseDirectory); | ||||
|  | ||||
|         var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args); | ||||
|  | ||||
|         appBuilder.RootComponents.Add<App>("#app"); | ||||
|  | ||||
|         appBuilder.Services.ThingsGatewayComponentsConfigureServices(); | ||||
|         var app = appBuilder.Build(); | ||||
|         app.MainWindow.SetTitle("ThingsGateway.Foundation.Demo"); | ||||
|         app.MainWindow.SetIconFile("wwwroot/favicon.ico"); | ||||
|         AppDomain.CurrentDomain.UnhandledException += (sender, error) => | ||||
|         { | ||||
|         }; | ||||
|  | ||||
|         app.Run(); | ||||
|     } | ||||
| } | ||||
| @@ -1,32 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk.Razor"> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<OutputType>WinExe</OutputType> | ||||
| 		<ApplicationIcon>favicon.ico</ApplicationIcon> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <None Remove="favicon.ico" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <Content Include="favicon.ico"> | ||||
| 	    <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
| 	    <ExcludeFromSingleFile>true</ExcludeFromSingleFile> | ||||
| 	    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> | ||||
| 	  </Content> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Photino.Blazor" Version="2.6.0" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <ProjectReference Include="..\ThingsGateway.Foundation.Demo.Rcl\ThingsGateway.Foundation.Demo.Rcl.csproj" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
|  | ||||
| </Project> | ||||
| @@ -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.Foundation.Demo | ||||
|  | ||||
| <Router AppAssembly="@typeof(App).Assembly"> | ||||
|     <Found Context="routeData"> | ||||
|         <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> | ||||
|         <FocusOnNavigate RouteData="@routeData" Selector="h1" /> | ||||
|     </Found> | ||||
|     <NotFound> | ||||
|         <LayoutView Layout="@typeof(MainLayout)"> | ||||
|             <p role="alert">Sorry, there's nothing at this address.</p> | ||||
|         </LayoutView> | ||||
|     </NotFound> | ||||
| </Router> | ||||
|  | ||||
| @@ -1,148 +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.AspNetCore.Components; | ||||
|  | ||||
| using ThingsGateway.Components; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Demo; | ||||
| using LogLevel = Microsoft.Extensions.Logging.LogLevel; | ||||
| /// <summary> | ||||
| /// 调试UI | ||||
| /// </summary> | ||||
| public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 日志缓存 | ||||
|     /// </summary> | ||||
|     public ConcurrentLinkedList<(LogLevel level, string message)> Messages = new(); | ||||
|  | ||||
|     private PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(1)); | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     ~DriverDebugUIBase() | ||||
|     { | ||||
|         this.SafeDispose(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 变量地址 | ||||
|     /// </summary> | ||||
|     public virtual string Address { get; set; } = "40001"; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 长度 | ||||
|     /// </summary> | ||||
|     public virtual int Length { get; set; } = 1; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 默认读写设备 | ||||
|     /// </summary> | ||||
|     public virtual IReadWrite Plc { get; set; } | ||||
|     /// <summary> | ||||
|     /// 写入值 | ||||
|     /// </summary> | ||||
|     public virtual string WriteValue { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 数据类型 | ||||
|     /// </summary> | ||||
|     protected virtual DataTypeEnum DataTypeEnum { get; set; } = DataTypeEnum.Int16; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     [Inject] | ||||
|     public InitTimezone InitTimezone { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public virtual void Dispose() | ||||
|     { | ||||
|         _periodicTimer?.Dispose(); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public void LogOut(ThingsGateway.Foundation.Core.LogLevel logLevel, object source, string message, Exception exception) | ||||
|     { | ||||
|         Messages.Add(((LogLevel)logLevel, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {message} {exception}")); | ||||
|         if (Messages.Count > 2500) | ||||
|         { | ||||
|             Messages.Clear(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public virtual async Task ReadAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var data = await Plc.ReadAsync(Address, Length, DataTypeEnum); | ||||
|             if (data.IsSuccess) | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Information, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 对应类型值:{Environment.NewLine}{data.Content.ToJsonString(true)} ")); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Warning, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}")); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             Messages.Add((LogLevel.Error, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 错误:{ex.Message}")); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public virtual async Task WriteAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var data = await Plc.WriteAsync(Address, WriteValue, Length, DataTypeEnum); | ||||
|             if (data.IsSuccess) | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Information, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}")); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Warning, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - {data.Message}")); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             Messages.Add((LogLevel.Error, | ||||
|             $"{DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)} - 写入前失败:{ex.Message}")); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         _ = RunTimerAsync(); | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|     private async Task RunTimerAsync() | ||||
|     { | ||||
|         while (await _periodicTimer.WaitForNextTickAsync()) | ||||
|         { | ||||
|             await InvokeAsync(StateHasChanged); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,205 +0,0 @@ | ||||
| @* | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| *@ | ||||
|  | ||||
| @using BlazorComponent; | ||||
| @using Microsoft.AspNetCore.Components.Web; | ||||
| @using Microsoft.JSInterop; | ||||
| @using ThingsGateway.Foundation.Core; | ||||
| @using Masa.Blazor; | ||||
| @namespace ThingsGateway.Foundation.Demo | ||||
| @inherits DriverDebugUIBase | ||||
|  | ||||
| <MCard Elevation="1" Rounded="false" Class=" pa-2" Style="width:100%"> | ||||
|     <MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters> | ||||
|  | ||||
|         <MCol Md="5"> | ||||
|             <MTabs @bind-Value="tab" Class="ma-2"> | ||||
|                 <MTab Value=1>   读写测试    </MTab> | ||||
|                 <MTab Value=2>    特殊功能    </MTab> | ||||
|                 <MTab Value=3>    代码示例    </MTab> | ||||
|             </MTabs> | ||||
|  | ||||
|             <MTabsItems Value="tab"> | ||||
|                 <MTabItem Value="1"> | ||||
|                     @if (tab == 1) | ||||
|                     { | ||||
|                         @if (ReadWriteContent == null) | ||||
|                         { | ||||
|  | ||||
|                             <div class="my-1 py-1"> | ||||
|                                 <MTooltip Bottom Context="tip"> | ||||
|                                     <ActivatorContent> | ||||
|                                         <MTextarea Class="mx-1 my-1" Label="变量地址" @attributes="@tip.Attrs" Dense Outlined HideDetails="@("auto")" @bind-Value=@Address /> | ||||
|                                     </ActivatorContent> | ||||
|                                     <ChildContent> | ||||
|                                         <span style="white-space: pre-wrap;">@Plc?.GetAddressDescription()</span> | ||||
|                                     </ChildContent> | ||||
|                                 </MTooltip> | ||||
|                                 <MRow Class="my-1" Justify="JustifyTypes.Start" Align="AlignTypes.Start" NoGutters> | ||||
|                                 <MTextField Class="mx-1 my-1" Style="max-width:200px" Label="读取长度" Dense Outlined HideDetails="@("auto")" @bind-Value=@Length /> | ||||
|                                     <MSelect Class="mx-1 my-1" Style="max-width:200px" @bind-Value="DataTypeEnum" Outlined Label="数据类型" | ||||
|                                              Items=@(typeof(DataTypeEnum).GetEnumListWithOutSugar()) | ||||
|                                              MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" | ||||
|                                              ItemText=@((u) =>u.Description) | ||||
|                                              ItemValue=@(u =>(DataTypeEnum)u.Value) | ||||
|                                              HideDetails=@("auto") Height="30" | ||||
|                                               Dense> | ||||
|                                 </MSelect> | ||||
|                             </MRow> | ||||
|  | ||||
|                             <MButton Class="mx-1 my-1" Color="primary" OnClick="ReadAsync"> | ||||
|                                 读取 | ||||
|                             </MButton> | ||||
|                             <MTextarea Class="mx-1 mt-3 my-1" Label="值" Dense Outlined HideDetails="@("auto")" @bind-Value=@WriteValue /> | ||||
|                                 <MButton Class="mx-1 my-1" Color="primary" OnClick="WriteAsync"> | ||||
|                                     写入 | ||||
|                                 </MButton> | ||||
|  | ||||
|                             </div> | ||||
|  | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             @ReadWriteContent | ||||
|                         } | ||||
|                     } | ||||
|                 </MTabItem> | ||||
|  | ||||
|                 <MTabItem Value="2"> | ||||
|                     @if (tab == 2) | ||||
|                     { | ||||
|                         @if (ShowDefaultOtherContent) | ||||
|                         { | ||||
|                             <MSubheader> | ||||
|                                 连读打包 | ||||
|                             </MSubheader> | ||||
|                             <MContainer> | ||||
|  | ||||
|                                 @foreach (var item in DeviceVariableRunTimes) | ||||
|                                 { | ||||
|                                     <MRow Dense Align="AlignTypes.Center"> | ||||
|                                         <MTextField Class="ma-1" Outlined Style="min-width:100px" Label=@(item.DescriptionWithOutSugar(x => x.VariableAddress)) Dense HideDetails="@("auto")" @bind-Value=@item.VariableAddress></MTextField> | ||||
|                                         <MSelect Class="mx-1 my-1" Style="max-width:120px" @bind-Value="item.DataTypeEnum" Outlined Label=@(item.DescriptionWithOutSugar(x => x.DataTypeEnum)) | ||||
|                                                  Items=@(typeof(DataTypeEnum).GetEnumListWithOutSugar()) | ||||
|                                                  MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" | ||||
|                                                  ItemText=@((u) =>u.Description) | ||||
|                                                  ItemValue=@(u =>(DataTypeEnum)u.Value) | ||||
|                                                  HideDetails=@("auto") Height="30" | ||||
|                                               Dense> | ||||
|                                     </MSelect> | ||||
|  | ||||
|                                     <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=@(item.DescriptionWithOutSugar(x => x.IntervalTime)) Dense HideDetails="@("auto")" @bind-Value=@item.IntervalTime></MTextField> | ||||
|  | ||||
|                                         <MTextField Class="ma-1" Outlined Style="max-width:100px" Label=实时值 Readonly ClearIcon="" Dense HideDetails="@("auto")" Value=item.Value?.ToJsonString()></MTextField> | ||||
|  | ||||
|                                     </MRow> | ||||
|                                 } | ||||
|                                 <MRow Dense> | ||||
|                                 <MTextField Class="ma-1" Outlined Style="max-width:100px" Label="打包长度" Dense HideDetails="@("auto")" @bind-Value=@MaxPack></MTextField> | ||||
|                                     <MButton Class="ma-1" Color="primary" OnClick="MulReadAsync"> | ||||
|                                         读取 | ||||
|                                     </MButton> | ||||
|                                 </MRow> | ||||
|                             </MContainer> | ||||
|  | ||||
|                         } | ||||
|  | ||||
|                         @if (OtherContent != null) | ||||
|                         { | ||||
|                             <MSheet Style="height:100%;overflow-y:auto"> | ||||
|                                 @OtherContent | ||||
|                             </MSheet> | ||||
|                         } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|                     } | ||||
|                 </MTabItem> | ||||
|  | ||||
|  | ||||
|                 <MTabItem Value="3"> | ||||
|                     @if (tab == 3) | ||||
|                     { | ||||
|                         @if (CodeContent != null) | ||||
|                             @CodeContent | ||||
|                         else | ||||
|                         { | ||||
|  | ||||
|                             <MRow Align="AlignTypes.Center"> | ||||
|                                 <MContainer> | ||||
|  | ||||
|                                     <MItemGroup @bind-Value="_selected" Class="shrink mr-6" Mandatory> | ||||
|                                     @{ | ||||
|  | ||||
|                                             int index = 0; | ||||
|  | ||||
|                                         } | ||||
|                                         <MRow> | ||||
|  | ||||
|                                             @foreach (var item in Sections) | ||||
|                                             { | ||||
|                                                 <MItem Value="@(index++)"> | ||||
|                                                     <div> | ||||
|                                                         <MButton IsActive="@context.Active" Icon OnClick="@context.Toggle"> | ||||
|                                                             <MIcon>mdi-record</MIcon> | ||||
|                                                         </MButton> | ||||
|                                                     </div> | ||||
|                                                 </MItem> | ||||
|                                             } | ||||
|                                         </MRow> | ||||
|                                     </MItemGroup> | ||||
|                                 </MContainer> | ||||
|  | ||||
|                                 <MCol> | ||||
|                                     <MWindow Value="_selected" Vertical Class="elevation-1 grey lighten-5 rounded-b" Style=@($"height:450px;overflow:auto")> | ||||
|                                         @{ | ||||
|                                             int index = 0; | ||||
|                                         } | ||||
|                                         @foreach (var item in Sections) | ||||
|                                         { | ||||
|                                             <MWindowItem Value="@(index++)"> | ||||
|                                                 <AppCode RoundedTop0 Code="@item.Code" Language="@item.Language" /> | ||||
|                                             </MWindowItem> | ||||
|                                         } | ||||
|                                     </MWindow> | ||||
|                                 </MCol> | ||||
|                             </MRow> | ||||
|  | ||||
|  | ||||
|                         } | ||||
|  | ||||
|  | ||||
|                     } | ||||
|                 </MTabItem> | ||||
|             </MTabsItems> | ||||
|  | ||||
|         </MCol> | ||||
|  | ||||
|         <MCol Md="7"> | ||||
|             <MCard Style="overflow-y:auto;width:100%" Elevation="0" Flat Class="ml-4"> | ||||
|                 <ConsoleTxt Messages="Messages" Height=500></ConsoleTxt> | ||||
|             </MCard> | ||||
|         </MCol> | ||||
|  | ||||
|     </MRow> | ||||
|  | ||||
| </MCard> | ||||
|  | ||||
|  | ||||
| @code { | ||||
|     StringNumber tab; | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -1,236 +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 Microsoft.AspNetCore.Components; | ||||
|  | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Demo; | ||||
|  | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public partial class DriverDebugUIPage : DriverDebugUIBase | ||||
| { | ||||
|     /// <summary> | ||||
|     /// DeviceVariableRunTimes | ||||
|     /// </summary> | ||||
|     public List<DeviceVariableRunTime> DeviceVariableRunTimes; | ||||
|     /// <summary> | ||||
|     /// MaxPack | ||||
|     /// </summary> | ||||
|     public int MaxPack = 100; | ||||
|     /// <summary> | ||||
|     /// MulReadAsync | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task MulReadAsync() | ||||
|     { | ||||
|         var deviceVariableSourceReads = Plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(DeviceVariableRunTimes, MaxPack); | ||||
|         foreach (var item in deviceVariableSourceReads) | ||||
|         { | ||||
|             var result = await Plc.ReadAsync(item.VariableAddress, item.Length); | ||||
|             if (result.IsSuccess) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     item.DeviceVariableRunTimes.PraseStructContent(Plc, result.Content); | ||||
|                     Messages.Add((Microsoft.Extensions.Logging.LogLevel.Information, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + result.Content.ToHexString(' '))); | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + ex.Message)); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|             else | ||||
|                 Messages.Add((Microsoft.Extensions.Logging.LogLevel.Warning, DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + result.Message)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private StringNumber _selected = 0; | ||||
|     /// <summary> | ||||
|     /// Sections | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public List<(string Code, string Language)> Sections { get; set; } = new(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ShowDefaultOtherContent | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public bool ShowDefaultOtherContent { get; set; } = true; | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         DeviceVariableRunTimes = new() | ||||
|             { | ||||
|                                 new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40001", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                                    new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40011", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                                    new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40031", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                                    new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40101", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|             }; | ||||
|         Sections.Add(( | ||||
| """ | ||||
|                 /// <inheritdoc/> | ||||
|                 public class DeviceVariableSourceRead : IDeviceVariableSourceRead<DeviceVariableRunTime> | ||||
|                 { | ||||
|                     /// <inheritdoc/> | ||||
|                     public TimerTick TimerTick { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     public string VariableAddress { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     public int Length { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     public List<DeviceVariableRunTime> DeviceVariableRunTimes { get; set; } = new List<DeviceVariableRunTime>(); | ||||
|                 } | ||||
|                 /// <inheritdoc/> | ||||
|                 public class DeviceVariableRunTime : IDeviceVariableRunTime | ||||
|                 { | ||||
|                     /// <inheritdoc/> | ||||
|                     [Description("读取间隔")] | ||||
|                     public int IntervalTime { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     [Description("变量地址")] | ||||
|                     public string VariableAddress { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     public int Index { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     public IThingsGatewayBitConverter ThingsGatewayBitConverter { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     [Description("数据类型")] | ||||
|                     public DataTypeEnum DataTypeEnum { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     [Description("实时值")] | ||||
|                     public object Value { get; set; } | ||||
|                     /// <inheritdoc/> | ||||
|                     public OperResult SetValue(object value) | ||||
|                     { | ||||
|                         Value = value; | ||||
|                         return OperResult.CreateSuccessResult(); | ||||
|                     } | ||||
|                 } | ||||
|                 public List<DeviceVariableRunTime> DeviceVariableRunTimes; | ||||
|                                  | ||||
|                 private static async Task ModbusClientAsync(IReadWrite plc) | ||||
|                 { | ||||
|                 DeviceVariableRunTimes = new() | ||||
|                 { | ||||
|                                 new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40001", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                                    new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40011", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                                    new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40031", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                                    new DeviceVariableRunTime() | ||||
|                                 { | ||||
|                                     DataTypeEnum=DataTypeEnum.Int16, | ||||
|                                     VariableAddress="40101", | ||||
|                                     IntervalTime=1000, | ||||
|                                 }, | ||||
|                 }; | ||||
|  | ||||
|                     #region 连读 | ||||
|                 var deviceVariableSourceReads = Plc.LoadSourceRead<DeviceVariableSourceRead, DeviceVariableRunTime>(DeviceVariableRunTimes, MaxPack); | ||||
|                 foreach (var item in deviceVariableSourceReads) | ||||
|                 { | ||||
|                     var result = await Plc.ReadAsync(item.VariableAddress, item.Length); | ||||
|                     if (result.IsSuccess) | ||||
|                     { | ||||
|                         item.DeviceVariableRunTimes.PraseStructContent(result.Content); | ||||
|                     } | ||||
|                 } | ||||
|                     #endregion | ||||
|  | ||||
|                 } | ||||
|                  | ||||
| """, "csharp")); | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 自定义模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment ReadWriteContent { get; set; } | ||||
|     /// <summary> | ||||
|     /// 自定义模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment OtherContent { get; set; } | ||||
|     /// <summary> | ||||
|     /// 自定义模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment CodeContent { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     ~DriverDebugUIPage() | ||||
|     { | ||||
|         this.SafeDispose(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public override IReadWrite Plc { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void Dispose() | ||||
|     { | ||||
|         Plc?.SafeDispose(); | ||||
|         base.Dispose(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="firstRender"></param> | ||||
|     protected override void OnAfterRender(bool firstRender) | ||||
|     { | ||||
|         base.OnAfterRender(firstRender); | ||||
|     } | ||||
| } | ||||
| @@ -1,47 +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 Masa.Blazor | ||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> | ||||
|     <div class="mb-4">通道配置</div> | ||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> | ||||
|         <MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(serialProperty.DescriptionWithOutSugar(x => x.PortName)) Dense HideDetails="@("auto")" @bind-Value=@serialProperty.PortName /> | ||||
|         <MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(serialProperty.DescriptionWithOutSugar(x => x.BaudRate)) Dense HideDetails="@("auto")" @bind-Value=@serialProperty.BaudRate /> | ||||
|         <MTextField Style="max-width:100px" Class="ma-1" Outlined Label=@(serialProperty.DescriptionWithOutSugar(x => x.DataBits)) Dense HideDetails="@("auto")" @bind-Value=@serialProperty.DataBits /> | ||||
|         <MSelect Class="ma-1 " Style="max-width:200px" Outlined @bind-Value="serialProperty.Parity" Label="@(serialProperty.DescriptionWithOutSugar(x => x.Parity))" | ||||
|                  Items=@(typeof(Parity).GetEnumListWithOutSugar()) | ||||
|                  MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" | ||||
|                  ItemText=@((u) =>u.Description) | ||||
|                  ItemValue=@(u =>(Parity)u.Value) | ||||
|                  HideDetails=@("auto") Height="30" | ||||
|                  Dense> | ||||
|         </MSelect> | ||||
|         <MSelect Class="ma-1 " Style="max-width:200px" Outlined @bind-Value="serialProperty.StopBits" Label="@(serialProperty.DescriptionWithOutSugar(x => x.StopBits))" | ||||
|                  Items=@(typeof(StopBits).GetEnumListWithOutSugar()) | ||||
|                  MenuProps="@(props => { props.Auto = true; props.OffsetY = true; })" | ||||
|                  ItemText=@((u) =>u.Description) | ||||
|                  ItemValue=@(u =>(StopBits)u.Value) | ||||
|                  HideDetails=@("auto") Height="30" | ||||
|                  Dense> | ||||
|         </MSelect> | ||||
|         <MButton Class="ma-1" OnClick=@ConnectAsync Color="primary"> | ||||
|             连接 | ||||
|         </MButton> | ||||
|         <MButton Class="ma-1" OnClick=@DisConnect Color="red"> | ||||
|             断开 | ||||
|         </MButton> | ||||
|     </MRow> | ||||
| </MCard> | ||||
| @@ -1,106 +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.Demo; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public partial class SerialSessionPage : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
|     private TouchSocketConfig config; | ||||
|  | ||||
|     private readonly SerialProperty serialProperty = new(); | ||||
|  | ||||
|     private SerialSession SerialSession { get; set; } = new(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public SerialSession GetSerialSession() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetSerialProperty(serialProperty); | ||||
|         //载入配置 | ||||
|         SerialSession.Setup(config); | ||||
|         return SerialSession; | ||||
|     } | ||||
|     private async Task ConnectAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             SerialSession.Close(); | ||||
|             await GetSerialSession().ConnectAsync(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private void DisConnect() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             SerialSession.Close(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|  | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="firstRender"></param> | ||||
|     protected override void OnAfterRender(bool firstRender) | ||||
|     { | ||||
|         if (firstRender) | ||||
|         { | ||||
|             var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|             LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|             config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|             SerialSession.Setup(config); | ||||
|         } | ||||
|         base.OnAfterRender(firstRender); | ||||
|     } | ||||
|  | ||||
|     private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception); | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public void Dispose() | ||||
|     { | ||||
|         SerialSession.SafeDispose(); | ||||
|     } | ||||
|     internal void StateHasChangedAsync() | ||||
|     { | ||||
|         StateHasChanged(); | ||||
|     } | ||||
| } | ||||
| @@ -1,34 +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 ThingsGateway.Foundation.Core; | ||||
| @using Masa.Blazor | ||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> | ||||
|     <div class="mb-4">通道配置</div> | ||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> | ||||
|  | ||||
|         <MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@IP /> | ||||
|         <MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@Port /> | ||||
|  | ||||
|         <MButton Class="ma-1" OnClick=@ConnectAsync Color="primary"> | ||||
|             连接 | ||||
|         </MButton> | ||||
|         <MButton Class="ma-1" OnClick=@DisConnect Color="red"> | ||||
|             断开 | ||||
|         </MButton> | ||||
|     </MRow> | ||||
| </MCard> | ||||
| @@ -1,116 +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.Demo; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public partial class TcpClientPage : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
|     private TouchSocketConfig config; | ||||
|     /// <summary> | ||||
|     /// IP | ||||
|     /// </summary> | ||||
|     private string IP = "127.0.0.1"; | ||||
|     /// <summary> | ||||
|     /// Port | ||||
|     /// </summary> | ||||
|     public int Port { get; set; } = 502; | ||||
|  | ||||
|     private TcpClient TcpClient { get; set; } = new(); | ||||
|  | ||||
|     private async Task ConnectAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             TcpClient.Close(); | ||||
|             await GetTcpClient().ConnectAsync(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|  | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private void DisConnect() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             TcpClient.Close(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|  | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public TcpClient GetTcpClient() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)); | ||||
|         //载入配置 | ||||
|         TcpClient.Setup(config); | ||||
|         return TcpClient; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|  | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="firstRender"></param> | ||||
|     protected override void OnAfterRender(bool firstRender) | ||||
|     { | ||||
|         if (firstRender) | ||||
|         { | ||||
|             var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|             LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|             config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|             config.SetRemoteIPHost(new IPHost(IP + ":" + Port)); | ||||
|             TcpClient.Setup(config); | ||||
|         } | ||||
|         base.OnAfterRender(firstRender); | ||||
|     } | ||||
|  | ||||
|     private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public void Dispose() | ||||
|     { | ||||
|         TcpClient.SafeDispose(); | ||||
|     } | ||||
|  | ||||
|     internal void StateHasChangedAsync() | ||||
|     { | ||||
|         StateHasChanged(); | ||||
|     } | ||||
| } | ||||
| @@ -1,38 +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 ThingsGateway.Foundation.Core; | ||||
| @using Masa.Blazor | ||||
|  | ||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> | ||||
|     <div class="mb-4">通道配置</div> | ||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> | ||||
|  | ||||
|         <MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@ip /> | ||||
|         <MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@port /> | ||||
|  | ||||
|         <MButton Class="ma-1" OnClick=@Connect Color="primary"> | ||||
|             连接 | ||||
|         </MButton> | ||||
|         <MButton Class="ma-1" OnClick=@DisConnect Color="red"> | ||||
|             断开 | ||||
|         </MButton> | ||||
|  | ||||
|  | ||||
|  | ||||
|     </MRow> | ||||
| </MCard> | ||||
| @@ -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.Foundation.Demo; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public partial class TcpServerPage : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
|     private TouchSocketConfig config; | ||||
|  | ||||
|     private string ip = "127.0.0.1"; | ||||
|  | ||||
|     private int port = 502; | ||||
|  | ||||
|     private TcpService TcpServer { get; set; } = new(); | ||||
|  | ||||
|     private void Connect() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             TcpServer.Stop(); | ||||
|             GetTcpServer().Start(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|  | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private void DisConnect() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             TcpServer.Stop(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public TcpService GetTcpServer() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); | ||||
|         //载入配置 | ||||
|         TcpServer.Setup(config); | ||||
|         return TcpServer; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|  | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="firstRender"></param> | ||||
|     protected override void OnAfterRender(bool firstRender) | ||||
|     { | ||||
|         if (firstRender) | ||||
|         { | ||||
|             var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|             LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|             config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|             config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); | ||||
|             TcpServer.Setup(config); | ||||
|         } | ||||
|         base.OnAfterRender(firstRender); | ||||
|     } | ||||
|  | ||||
|     private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception); | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public void Dispose() | ||||
|     { | ||||
|         TcpServer.SafeDispose(); | ||||
|     } | ||||
|     internal void StateHasChangedAsync() | ||||
|     { | ||||
|         StateHasChanged(); | ||||
|     } | ||||
| } | ||||
| @@ -1,37 +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 ThingsGateway.Foundation.Core; | ||||
| @using Masa.Blazor | ||||
|  | ||||
| <MCard Elevation="1" Rounded="false" Class="pa-2" Style="width:100%"> | ||||
|     <div class="mb-4">通道配置</div> | ||||
|     <MRow Justify="JustifyTypes.Start" Align="AlignTypes.Center"> | ||||
|  | ||||
|         <MTextField Class="ma-1" Style="max-width:100px" Label="IP地址" Dense Outlined HideDetails="@("auto")" @bind-Value=@IP /> | ||||
|         <MTextField Class="ma-1" Style="max-width:100px" Label="端口" Dense Outlined HideDetails="@("auto")" @bind-Value=@Port /> | ||||
|  | ||||
|         <MButton Class="ma-1" OnClick=Connect Color="primary"> | ||||
|             连接 | ||||
|         </MButton> | ||||
|         <MButton Class="ma-1" OnClick=DisConnect Color="red"> | ||||
|             断开 | ||||
|         </MButton> | ||||
|  | ||||
|  | ||||
|     </MRow> | ||||
| </MCard> | ||||
| @@ -1,113 +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.Demo; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public partial class UdpSessionPage : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
|     private TouchSocketConfig config; | ||||
|     /// <summary> | ||||
|     /// IP | ||||
|     /// </summary> | ||||
|     public string IP = "127.0.0.1"; | ||||
|     /// <summary> | ||||
|     /// Port | ||||
|     /// </summary> | ||||
|     public int Port = 502; | ||||
|  | ||||
|     private UdpSession UdpSession { get; set; } = new(); | ||||
|  | ||||
|     private void Connect() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             UdpSession.Stop(); | ||||
|             GetUdpSession().Start(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private void DisConnect() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             UdpSession.Stop(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|  | ||||
|             LogAction?.Invoke(LogLevel.Error, null, null, ex); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public UdpSession GetUdpSession() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)); | ||||
|         config.SetBindIPHost(new IPHost(0)); | ||||
|         //载入配置 | ||||
|         UdpSession.Setup(config); | ||||
|         return UdpSession; | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         config ??= new TouchSocketConfig(); | ||||
|  | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="firstRender"></param> | ||||
|     protected override void OnAfterRender(bool firstRender) | ||||
|     { | ||||
|         if (firstRender) | ||||
|         { | ||||
|             var LogMessage = new LoggerGroup() { LogLevel = LogLevel.Trace }; | ||||
|             LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = LogLevel.Trace }); | ||||
|             config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|             config.SetRemoteIPHost(new IPHost(IP + ":" + Port)); | ||||
|             config.SetBindIPHost(new IPHost(0)); | ||||
|             UdpSession.Setup(config); | ||||
|         } | ||||
|         base.OnAfterRender(firstRender); | ||||
|     } | ||||
|     private void LogOut(LogLevel logLevel, object source, string message, Exception exception) => LogAction?.Invoke(logLevel, source, message, exception); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public void Dispose() | ||||
|     { | ||||
|         UdpSession.SafeDispose(); | ||||
|     } | ||||
|     internal void StateHasChangedAsync() | ||||
|     { | ||||
|         StateHasChanged(); | ||||
|     } | ||||
| } | ||||
| @@ -1,42 +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.Demo; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class DeviceVariableRunTime : IDeviceVariableRunTime | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     [Description("读取间隔")] | ||||
|     public int IntervalTime { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     [Description("变量地址")] | ||||
|     public string VariableAddress { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public int Index { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public IThingsGatewayBitConverter ThingsGatewayBitConverter { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     [Description("数据类型")] | ||||
|     public DataTypeEnum DataTypeEnum { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     [Description("实时值")] | ||||
|     public object Value { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public OperResult SetValue(object value, DateTime dateTime = default, bool isOnline = true) | ||||
|     { | ||||
|         Value = value; | ||||
|         return OperResult.CreateSuccessResult(); | ||||
|     } | ||||
| } | ||||
| @@ -1,28 +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; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Demo; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class DeviceVariableSourceRead : IDeviceVariableSourceRead<IDeviceVariableRunTime> | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public TimerTick TimerTick { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public string VariableAddress { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public int Length { get; set; } | ||||
|     /// <inheritdoc/> | ||||
|     public List<IDeviceVariableRunTime> DeviceVariableRunTimes { get; set; } = new List<IDeviceVariableRunTime>(); | ||||
| } | ||||
| @@ -1,21 +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 System; | ||||
| global using System.Threading; | ||||
| global using System.Threading.Tasks; | ||||
|  | ||||
| global using ThingsGateway.Components; | ||||
| global using ThingsGateway.Foundation.Core; | ||||
| global using ThingsGateway.Foundation.Serial; | ||||
| global using ThingsGateway.Foundation.Sockets; | ||||
|  | ||||
| @@ -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.Foundation.Demo | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
|  | ||||
| @code { | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="firstRender"></param> | ||||
|     /// <returns></returns> | ||||
|     protected override async Task OnAfterRenderAsync(bool firstRender) | ||||
|     { | ||||
|         if (firstRender) | ||||
|         { | ||||
|             NavigationManager.NavigateTo("index"); | ||||
|         } | ||||
|  | ||||
|         await base.OnAfterRenderAsync(firstRender); | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -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,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.Foundation.Demo | ||||
| @inherits LayoutComponentBase | ||||
|  | ||||
| <CascadingValue Value="IsMobile" Name="IsMobile"> | ||||
|     <MApp> | ||||
|         <MErrorHandler> | ||||
|             @Body | ||||
|         </MErrorHandler> | ||||
|     </MApp> | ||||
| </CascadingValue> | ||||
|  | ||||
| @code { | ||||
|     public bool IsMobile { get; set; } | ||||
|     [Inject] | ||||
|     public MasaBlazor MasaBlazor { get; set; } | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         base.OnInitialized(); | ||||
|         MasaBlazor.BreakpointChanged += BreakpointOnOnUpdate; | ||||
|     } | ||||
|  | ||||
|     private void BreakpointOnOnUpdate(object sender, BreakpointChangedEventArgs e) | ||||
|     { | ||||
|         IsMobile = MasaBlazor.Breakpoint.Mobile; | ||||
|         if (e.MobileChanged) | ||||
|         { | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,77 +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 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"; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,223 +0,0 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD>Ϊȫ<CEAA>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD> | ||||
| //  <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>룩<EFBFBD><EBA3A9><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><DFB1><EFBFBD>Diego<67><6F><EFBFBD><EFBFBD> | ||||
| //  Դ<><D4B4><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ֿ<EFBFBD><D6BF>Ŀ<EFBFBD>ԴЭ<D4B4>鼰<EFBFBD><E9BCB0><EFBFBD><EFBFBD>Э<EFBFBD><D0AD> | ||||
| //  GiteeԴ<65><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway | ||||
| //  GithubԴ<62><D4B4><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<><CAB9><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<51><C8BA>605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Demo; | ||||
|  | ||||
| public partial class MainLayout | ||||
| { | ||||
|  | ||||
|     private List<NavItem> Navs { get; set; } = new(); | ||||
|     private List<PageTabItem> pageTabItems { get; set; } = new(); | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         var dataString = | ||||
| """ | ||||
| [ | ||||
|   { | ||||
|     "Href": "/index", | ||||
|     "Title": "<22><>ҳ" | ||||
|   }, | ||||
|   { | ||||
|     "Title": "Modbus", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/ModbusRtu", | ||||
|         "Title": "ModbusRtu" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusTcp", | ||||
|         "Title": "ModbusTcp" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusRtuOverTcp", | ||||
|         "Title": "ModbusRtuOverTcp" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusRtuOverUdp", | ||||
|         "Title": "ModbusRtuOverUdp" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusUdp", | ||||
|         "Title": "ModbusUdp" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusTcpDtu", | ||||
|         "Title": "ModbusTcpDtu" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusTcpServer", | ||||
|         "Title": "ModbusTcpServer" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/ModbusSerialServer", | ||||
|         "Title": "ModbusSerialServer" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "Siemens", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/S7_1500", | ||||
|         "Title": "S7_1500" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/S7_1200", | ||||
|         "Title": "S7_1200" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/S7_200", | ||||
|         "Title": "S7_200" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/S7_200SMART", | ||||
|         "Title": "S7_200SMART" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/S7_300", | ||||
|         "Title": "S7_400" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/S7_400", | ||||
|         "Title": "S7_400" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "DLT645", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/DLT645_2007", | ||||
|         "Title": "DLT645_2007" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/DLT645_2007OverTcp", | ||||
|         "Title": "DLT645_2007OverTcp" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "OPCDA", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/OPCDAClient", | ||||
|         "Title": "OPCDAClient" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "OPCUA", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/OPCUAClient", | ||||
|         "Title": "OPCUAClient" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "Mqtt", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/MqttClient", | ||||
|         "Title": "MqttClient" | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|  | ||||
|  | ||||
| """; | ||||
|         Navs = dataString.FromJsonString<List<NavItem>>(); | ||||
|  | ||||
| #if Pro | ||||
|         var dataStringPro = | ||||
| """ | ||||
| [ | ||||
|   { | ||||
|     "Title": "ABCIP", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/ABCIPTCP", | ||||
|         "Title": "ABCIPTCP" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "Omron", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/OmronFinsTcp", | ||||
|         "Title": "OmronFinsTcp" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/OmronFinsUdp", | ||||
|         "Title": "OmronFinsUdp" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "Secs", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/SecsTcp", | ||||
|         "Title": "SecsTcp" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "TS550", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/TS550", | ||||
|         "Title": "TS550" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "Vigor", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/VigorSerial", | ||||
|         "Title": "VigorSerial" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/VigorSerialOverTcp", | ||||
|         "Title": "VigorSerialOverTcp" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "Title": "GasCustom", | ||||
|     "Children": [ | ||||
|       { | ||||
|         "Href": "/GasCustomSerial", | ||||
|         "Title": "GasCustomSerial" | ||||
|       }, | ||||
|       { | ||||
|         "Href": "/GasCustomSerialOverTcp", | ||||
|         "Title": "GasCustomSerialOverTcp" | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
|  | ||||
| ] | ||||
|  | ||||
|  | ||||
| """; | ||||
|         Navs.AddRange(dataStringPro.FromJsonString<List<NavItem>>()); | ||||
| #endif | ||||
|         pageTabItems = Navs.PasePageTabItem(); | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
| } | ||||
| @@ -1,140 +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" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\MqttRpcNameVaueWithId.cs" Link="Pages\Mqtt\MqttRpcNameVaueWithId.cs" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor.cs" Link="Pages\Mqtt\MqttClientDebugPage.razor.cs" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor.cs" Link="Pages\Mqtt\MqttClientPage.razor.cs" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\PrivateLogger.cs" Link="Pages\Mqtt\PrivateLogger.cs" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClient.cs" Link="Pages\Mqtt\MqttRpcClient.cs" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcClientExtensions.cs" Link="Pages\Mqtt\MqttRpcClientExtensions.cs" /> | ||||
| 		<Compile Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\RpcClass\MqttRpcTopicPair.cs" Link="Pages\Mqtt\MqttRpcTopicPair.cs" /> | ||||
| 		<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> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <Folder Include="Pages\Mqtt\" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientDebugPage.razor" Link="Pages\Mqtt\MqttClientDebugPage.razor" /> | ||||
| 	  <Content Include="..\..\Plugin\ThingsGateway.Plugin.Mqtt\Page\MqttClientPage.razor" Link="Pages\Mqtt\MqttClientPage.razor" /> | ||||
| 		<PackageReference Include="MQTTnet" Version="4.3.1.873" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
|  | ||||
| </Project> | ||||
| @@ -1,29 +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 ThingsGateway.Foundation.Core; | ||||
| @using ThingsGateway.Components; | ||||
| @using ThingsGateway.Core; | ||||
| @using System.Net.Http.Json | ||||
| @using System.IO; | ||||
| @using System.Text.Json; | ||||
| @using ThingsGateway.Foundation.Serial; | ||||
| @using ThingsGateway.Foundation.Sockets; | ||||
| @@ -1,41 +0,0 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="utf-8" /> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" /> | ||||
|     <title>ThingsGateway.Foundation.Demo</title> | ||||
|     <base href="/" /> | ||||
|  | ||||
|     <link rel="icon" href="favicon.ico" type="image/x-icon"> | ||||
|  | ||||
|  | ||||
|     <link href="_content/Masa.Blazor/css/masa-blazor.min.css" rel="stylesheet" /> | ||||
|     <link href="_content/ThingsGateway.Components/css/materialdesign/v7.1.96/css/materialdesignicons.min.css" rel="stylesheet"> | ||||
|     <link href="_content/ThingsGateway.Components/css/material/icons.css" rel="stylesheet"> | ||||
|     <link href="_content/ThingsGateway.Components/css/fontawesome/v6.4.0/css/all.min.css" rel="stylesheet"> | ||||
|     <link href="_content/ThingsGateway.Components/style/custom.css" rel="stylesheet"> | ||||
|     <link href="_content/ThingsGateway.Components/prism/prism-material-dark-for-masa.css" rel="stylesheet"> | ||||
|     <link href="_content/ThingsGateway.Components/prism/prism-line-highlight.min.css" rel="stylesheet"> | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|     <div id="app"></div> | ||||
|  | ||||
|     <div id="blazor-error-ui"> | ||||
|         <span> | ||||
|             <environment include="Staging,Production"> | ||||
|                 An error has occurred. This application may no longer respond until reloaded. | ||||
|             </environment> | ||||
|             <environment include="Development"> | ||||
|                 An unhandled exception has occurred. See browser dev tools for details. | ||||
|             </environment> | ||||
|         </span> | ||||
|         <a href="" class="reload">Reload</a> | ||||
|         <a class="dismiss">🗙</a> | ||||
|     </div> | ||||
|  | ||||
|     <script src="_framework/blazor.webview.js" autostart="true"></script> | ||||
|     <script src="_content/ThingsGateway.Components/prism/prism.min.js"></script> | ||||
|     <script src="_content/BlazorComponent/js/blazor-component.js"></script> | ||||
| </body> | ||||
| </html> | ||||
| @@ -1,46 +0,0 @@ | ||||
| <Project> | ||||
| 	<PropertyGroup> | ||||
| 		<Version>3.0.0.5</Version> | ||||
| 		<GenerateDocumentationFile>True</GenerateDocumentationFile> | ||||
| 		<LangVersion>latest</LangVersion> | ||||
| 		<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks> | ||||
| 		<Authors>Diego</Authors> | ||||
| 		<Product>ThingsGateway</Product> | ||||
| 		<Copyright>© 2023-present Diego</Copyright> | ||||
| 		<RepositoryUrl>https://gitee.com/diego2098/ThingsGateway</RepositoryUrl> | ||||
| 		<PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
| 		<EmbedUntrackedSource>true</EmbedUntrackedSource> | ||||
| 		<EmbedAllSources>true</EmbedAllSources> | ||||
| 		<RepositoryType>Gitee</RepositoryType> | ||||
| 		<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||||
| 		<PackageReadmeFile>README.md</PackageReadmeFile> | ||||
| 		<PackageIcon>icon.png</PackageIcon> | ||||
| 		<IncludeSymbols>true</IncludeSymbols> | ||||
| 		<SymbolPackageFormat>snupkg</SymbolPackageFormat> | ||||
| 		<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> | ||||
| 		<PackageProjectUrl>https://diego2098.gitee.io/thingsgateway-docs/</PackageProjectUrl> | ||||
| 		<PackageTags>ThingsGateway;Diego;dotNET China;Blazor;设备采集;边缘网关</PackageTags> | ||||
| 		<SignAssembly>True</SignAssembly> | ||||
| 		<DelaySign>False</DelaySign> | ||||
| 		<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages> | ||||
| 		<PackageOutputPath>../../nupkgs</PackageOutputPath> | ||||
| 		<AssemblyOriginatorKeyFile>../../../snks/ThingsGateway.snk</AssemblyOriginatorKeyFile> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<None Include="..\..\..\README.md" Pack="true" PackagePath="\" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<None Include="..\..\..\icon.png"> | ||||
| 			<Pack>True</Pack> | ||||
| 			<PackagePath></PackagePath> | ||||
| 		</None> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
| </Project> | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,480 +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; | ||||
|  | ||||
| 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,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 | ||||
|  | ||||
| using System.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.String; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
|  | ||||
| /// <summary> | ||||
| /// DLT645_2007Address | ||||
| /// </summary> | ||||
| public class DLT645_2007Address : DeviceAddressBase | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public DLT645_2007Address() | ||||
|     { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 数据标识 | ||||
|     /// </summary> | ||||
|     public byte[] DataId { get; set; } = new byte[0]; | ||||
|     /// <summary> | ||||
|     /// 反转解析 | ||||
|     /// </summary> | ||||
|     public bool Reverse { get; set; } = true; | ||||
|     /// <summary> | ||||
|     /// 站号信息 | ||||
|     /// </summary> | ||||
|     public byte[] Station { get; set; } = new byte[0]; | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     /// <param name="address"></param> | ||||
|     /// <returns></returns> | ||||
|     public static DLT645_2007Address ParseFrom(string address) | ||||
|     { | ||||
|         DLT645_2007Address dLT645_2007Address = new(); | ||||
|         byte[] array; | ||||
|         array = new byte[0]; | ||||
|         if (address.IndexOf(';') < 0) | ||||
|         { | ||||
|             array = address.ByHexStringToBytes().Reverse().ToArray(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             string[] strArray = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); | ||||
|  | ||||
|             for (int index = 0; index < strArray.Length; ++index) | ||||
|             { | ||||
|                 if (strArray[index].ToUpper().StartsWith("S=")) | ||||
|                 { | ||||
|                     var station = strArray[index].Substring(2); | ||||
|                     if (station.IsNullOrEmpty()) station = string.Empty; | ||||
|                     if (station.Length < 12) | ||||
|                         station = station.PadLeft(12, '0'); | ||||
|                     dLT645_2007Address.Station = station.ByHexStringToBytes().Reverse().ToArray(); | ||||
|                 } | ||||
|                 else if (strArray[index].Contains("r=")) | ||||
|                 { | ||||
|                     dLT645_2007Address.Reverse = strArray[index].Substring(2).GetBoolValue(); | ||||
|                 } | ||||
|                 else if (!strArray[index].Contains("=")) | ||||
|                 { | ||||
|                     array = strArray[index].ByHexStringToBytes().Reverse().ToArray(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         dLT645_2007Address.DataId = array; | ||||
|         return dLT645_2007Address; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         StringBuilder stringGeter = new(); | ||||
|         if (Station.Length > 0) | ||||
|         { | ||||
|             stringGeter.Append("s=" + Station.Reverse().ToArray().ToHexString() + ";"); | ||||
|         } | ||||
|         if (DataId.Length > 0) | ||||
|         { | ||||
|             stringGeter.Append(DataId.Reverse().ToArray().ToHexString() + ";"); | ||||
|         } | ||||
|         if (!Reverse) | ||||
|         { | ||||
|             stringGeter.Append("s=" + Reverse.ToString() + ";"); | ||||
|         } | ||||
|         return stringGeter.ToString(); | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,117 +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.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
| /// <summary> | ||||
| /// DLT645_2007 | ||||
| /// </summary> | ||||
| public class DLT645_2007BitConverter : ThingsGatewayBitConverter | ||||
| { | ||||
|     /// <summary> | ||||
|     /// DLT645_2007 | ||||
|     /// </summary> | ||||
|     public DLT645_2007BitConverter(EndianType endianType) : base(endianType) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// DLT645协议转换double | ||||
|     /// </summary> | ||||
|     /// <param name="buffer">带数据项标识</param> | ||||
|     /// <param name="offset"></param> | ||||
|     /// <returns></returns> | ||||
|     public override double ToDouble(byte[] buffer, int offset) | ||||
|     { | ||||
|         return Convert.ToDouble(this.ToString(buffer, offset, buffer.Length)); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override IThingsGatewayBitConverter CopyNew() | ||||
|     { | ||||
|         return new DLT645_2007BitConverter(EndianType) | ||||
|         { | ||||
|             DataFormat = DataFormat, | ||||
|             BcdFormat = BcdFormat, | ||||
|             Encoding = Encoding, | ||||
|             IsStringReverseByteWord = IsStringReverseByteWord, | ||||
|             Length = Length, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString(byte[] buffer) | ||||
|     { | ||||
|         return this.ToString(buffer, 0, buffer.Length); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString(byte[] buffer, int offset, int length) | ||||
|     { | ||||
|         buffer = buffer.RemoveBegin(offset); | ||||
|         buffer = buffer.BytesAdd(-0x33); | ||||
|         var dataInfos = DLT645Helper.GetDataInfos(buffer); | ||||
|         StringBuilder stringBuilder = new(); | ||||
|         foreach (var dataInfo in dataInfos) | ||||
|         { | ||||
|             //实际数据 | ||||
|             var content = buffer.SelectMiddle(4, dataInfo.ByteLength).Reverse().ToArray(); | ||||
|             if (dataInfo.IsSigned)//可能为负数 | ||||
|             { | ||||
|                 if (content[0] > 0x80)//最高位是表示正负 | ||||
|                 { | ||||
|                     content[0] = (byte)(content[0] - 0x80); | ||||
|                     if (dataInfo.Digtal == 0)//无小数点 | ||||
|                     { | ||||
|                         stringBuilder.Append($"-{content.ToHexString()}"); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         stringBuilder.Append((-(Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString()); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ToString(stringBuilder, dataInfo, content); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 ToString(stringBuilder, dataInfo, content); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return stringBuilder.ToString(); | ||||
|  | ||||
|         static void ToString(StringBuilder stringBuilder, DataInfo dataInfo, byte[] content) | ||||
|         { | ||||
|             if (dataInfo.Digtal < 0) | ||||
|             { | ||||
|                 stringBuilder.Append($"{Encoding.ASCII.GetString(content)}"); | ||||
|             } | ||||
|             else if (dataInfo.Digtal == 0)//无小数点 | ||||
|             { | ||||
|                 stringBuilder.Append($"{content.ToHexString()}"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 stringBuilder.Append(((Convert.ToDouble(content.ToHexString()) / Math.Pow(10.0, dataInfo.Digtal))).ToString()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,191 +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; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.DLT645; | ||||
|  | ||||
| /// <summary> | ||||
| /// DLT645_2007DataHandleAdapter | ||||
| /// </summary> | ||||
| public class DLT645_2007DataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<DLT645_2007Message> | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 增加FE FE FE FE的报文头部 | ||||
|     /// </summary> | ||||
|     [Description("前导符报文头")] | ||||
|     public bool EnableFEHead { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         //打包时加上4个FE字节 | ||||
|         if (EnableFEHead) | ||||
|         { | ||||
|             return DataTransUtil.SpliceArray(new byte[4] { 0xFE, 0xFE, 0xFE, 0xFE }, command); | ||||
|         } | ||||
|         return command; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override DLT645_2007Message GetInstance() | ||||
|     { | ||||
|         return new DLT645_2007Message(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(DLT645_2007Message request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         //因为设备可能带有FE前导符开头,这里找到0x68的位置 | ||||
|         int headCodeIndex = -1; | ||||
|         if (response != null) | ||||
|         { | ||||
|             for (int index = 0; index < response.Length; index++) | ||||
|             { | ||||
|                 if (response[index] == 0x68) | ||||
|                 { | ||||
|                     headCodeIndex = index; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         int sendHeadCodeIndex = 0; | ||||
|         if (send != null) | ||||
|         { | ||||
|             for (int index = 0; index < send.Length; index++) | ||||
|             { | ||||
|                 if (send[index] == 0x68) | ||||
|                 { | ||||
|                     sendHeadCodeIndex = index; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         //帧起始符 地址域  帧起始符 控制码 数据域长度共10个字节 | ||||
|         if (headCodeIndex < 0 || headCodeIndex + 10 > response.Length) | ||||
|             return FilterResult.Cache; | ||||
|  | ||||
|  | ||||
|         var len = 10 + response[headCodeIndex + 9] + 2; | ||||
|  | ||||
|         if (response.Length - headCodeIndex < len) | ||||
|         { | ||||
|             return FilterResult.Cache; | ||||
|         } | ||||
|         if (response.Length - headCodeIndex >= len && response[len + headCodeIndex - 1] == 0x16) | ||||
|         { | ||||
|  | ||||
|             //检查校验码 | ||||
|             int sumCheck = 0; | ||||
|             for (int i = headCodeIndex; i < len + headCodeIndex - 2; i++) | ||||
|                 sumCheck += response[i]; | ||||
|             if ((byte)sumCheck != response[len + headCodeIndex - 2]) | ||||
|             { | ||||
|                 //校验错误 | ||||
|                 request.Message = "和校验错误"; | ||||
|                 request.ErrorCode = 999; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|  | ||||
|             if ( | ||||
|                 (response[headCodeIndex + 1] != send[sendHeadCodeIndex + 1]) || | ||||
|                 (response[headCodeIndex + 2] != send[sendHeadCodeIndex + 2]) || | ||||
|                 (response[headCodeIndex + 3] != send[sendHeadCodeIndex + 3]) || | ||||
|                 (response[headCodeIndex + 4] != send[sendHeadCodeIndex + 4]) || | ||||
|                 (response[headCodeIndex + 5] != send[sendHeadCodeIndex + 5]) || | ||||
|                 (response[headCodeIndex + 6] != send[sendHeadCodeIndex + 6]) | ||||
|                 )//设备地址不符合时,返回错误 | ||||
|             { | ||||
|  | ||||
|                 if ( | ||||
|                 (send[sendHeadCodeIndex + 1] == 0xAA) && | ||||
|                 (send[sendHeadCodeIndex + 2] == 0xAA) && | ||||
|                 (send[sendHeadCodeIndex + 3] == 0xAA) && | ||||
|                 (send[sendHeadCodeIndex + 4] == 0xAA) && | ||||
|                 (send[sendHeadCodeIndex + 5] == 0xAA) && | ||||
|                 (send[sendHeadCodeIndex + 6] == 0xAA) | ||||
|                 )//读写通讯地址例外 | ||||
|                 { | ||||
|  | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     request.Message = "返回地址不符合规则"; | ||||
|                     request.ErrorCode = 999; | ||||
|                     return FilterResult.Success; | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|  | ||||
|  | ||||
|             if ((response[headCodeIndex + 8] != send[sendHeadCodeIndex + 8] + 0x80))//控制码不符合时,返回错误 | ||||
|             { | ||||
|                 request.Message = "返回控制码:" + $"0x{response[headCodeIndex + 8]:X2},请求控制码:" + $"0x{send[sendHeadCodeIndex + 8]:X2},不符合规则"; | ||||
|                 request.ErrorCode = 999; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|             if ((response[headCodeIndex + 8] & 0x40) == 0x40)//控制码bit6为1时,返回错误 | ||||
|             { | ||||
|                 byte byte1 = (byte)(response[headCodeIndex + 10] - 0x33); | ||||
|                 var error = DLT645Helper.Get2007ErrorMessage(byte1); | ||||
|                 request.Message = "异常控制码:" + $"0x{response[headCodeIndex + 8]:X2},错误信息:{error}"; | ||||
|                 request.ErrorCode = 999; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|  | ||||
|             if (send[sendHeadCodeIndex + 8] == (byte)ControlCode.Read || | ||||
|     send[sendHeadCodeIndex + 8] == (byte)ControlCode.Write | ||||
|     ) | ||||
|             { | ||||
|                 //数据标识不符合时,返回错误 | ||||
|                 if ( | ||||
|                 (response[headCodeIndex + 10] == send[sendHeadCodeIndex + 10]) && | ||||
|                 (response[headCodeIndex + 11] == send[sendHeadCodeIndex + 11]) && | ||||
|                 (response[headCodeIndex + 12] == send[sendHeadCodeIndex + 12]) && | ||||
|                 (response[headCodeIndex + 13] == send[sendHeadCodeIndex + 13]) | ||||
|                 ) | ||||
|                 { | ||||
|  | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     request.Message = "返回数据标识不符合规则"; | ||||
|                     request.ErrorCode = 999; | ||||
|                     return FilterResult.Success; | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|  | ||||
|             request.Content = response.RemoveBegin(headCodeIndex + 10).RemoveLast(response.Length + 2 - len - headCodeIndex); | ||||
|             request.ErrorCode = 0; | ||||
|             return FilterResult.Success; | ||||
|  | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             request.ErrorCode = 999; | ||||
|             return FilterResult.Success; | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,34 +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.Adapter.DLT645; | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public class DLT645_2007Message : MessageBase, IMessage | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public override int HeadBytesLength => -1; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override bool CheckHeadBytes(byte[] head) | ||||
|     { | ||||
|         BodyLength = -1; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void SendBytesThen() | ||||
|     { | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,480 +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; | ||||
|  | ||||
| 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,44 +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.Adapter.DLT645; | ||||
|  | ||||
| internal static class PackHelper | ||||
| { | ||||
|     public static List<T> LoadSourceRead<T, T2>(IReadWrite device, List<T2> deviceVariables, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new() | ||||
|     { | ||||
|         var byteConverter = device.ThingsGatewayBitConverter; | ||||
|         var result = new List<T>(); | ||||
|         //需要先剔除额外信息,比如dataformat等 | ||||
|         foreach (var item in deviceVariables) | ||||
|         { | ||||
|             var address = item.VariableAddress; | ||||
|  | ||||
|             IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter); | ||||
|             item.ThingsGatewayBitConverter = transformParameter; | ||||
|             //item.VariableAddress = address; | ||||
|             item.Index = device.GetBitOffset(item.VariableAddress); | ||||
|  | ||||
|             result.Add(new() | ||||
|             { | ||||
|                 DeviceVariableRunTimes = new() { item }, | ||||
|                 VariableAddress = address, | ||||
|                 Length = 1, | ||||
|             }); | ||||
|         } | ||||
|         return result; | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,21 +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 System; | ||||
| global using System.Collections.Generic; | ||||
| global using System.Linq; | ||||
| global using System.Threading; | ||||
| global using System.Threading.Tasks; | ||||
|  | ||||
| global using ThingsGateway.Foundation.Core; | ||||
| global using ThingsGateway.Foundation.Serial; | ||||
| global using ThingsGateway.Foundation.Sockets; | ||||
| @@ -1,5 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| @@ -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.Core.EndianType)"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToDouble(System.Byte[],System.Int32)"> | ||||
|             <summary> | ||||
|             DLT645协议转换double | ||||
|             </summary> | ||||
|             <param name="buffer">带数据项标识</param> | ||||
|             <param name="offset"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007BitConverter.ToString(System.Byte[],System.Int32,System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter"> | ||||
|             <summary> | ||||
|             DLT645_2007DataHandleAdapter | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.EnableFEHead"> | ||||
|             <summary> | ||||
|             增加FE FE FE FE的报文头部 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007DataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.DLT645_2007Message,System.Byte[],System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp"> | ||||
|             <summary> | ||||
|             DLT645_2007 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.DLT645.DLT645_2007OverTcp.#ctor(ThingsGateway.Foundation.Core.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,21 +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 System; | ||||
| global using System.Collections.Generic; | ||||
| global using System.Linq; | ||||
| global using System.Threading; | ||||
| global using System.Threading.Tasks; | ||||
|  | ||||
| global using ThingsGateway.Foundation.Core; | ||||
| global using ThingsGateway.Foundation.Serial; | ||||
| global using ThingsGateway.Foundation.Sockets; | ||||
| @@ -1,175 +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.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension; | ||||
| using ThingsGateway.Foundation.Extension.String; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// Modbus协议地址 | ||||
| /// </summary> | ||||
| public class ModbusAddress : DeviceAddressBase | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public ModbusAddress() | ||||
|     { | ||||
|  | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 读取功能码 | ||||
|     /// </summary> | ||||
|     public ushort AddressStart => Address.ToUShort(); | ||||
|     /// <summary> | ||||
|     /// 读取功能码 | ||||
|     /// </summary> | ||||
|     public byte ReadFunction { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 站号信息 | ||||
|     /// </summary> | ||||
|     public byte Station { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入功能码 | ||||
|     /// </summary> | ||||
|     public byte WriteFunction { get; set; } | ||||
|     /// <summary> | ||||
|     /// 打包临时写入,需要读取的字节长度 | ||||
|     /// </summary> | ||||
|     public int ByteLength { get; set; } | ||||
|     /// <summary> | ||||
|     /// BitIndex | ||||
|     /// </summary> | ||||
|     public int BitIndex => (int)(Address.SplitDot().LastOrDefault().ToInt()); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 读取功能码 | ||||
|     /// </summary> | ||||
|     public ushort AddressEnd => (ushort)(AddressStart + (Math.Ceiling(ByteLength / 2.0) > 0 ? Math.Ceiling(ByteLength / 2.0) : 1)); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 作为Slave时需提供的SocketId,用于分辨Socket客户端,通常对比的是初始链接时的注册包 | ||||
|     /// </summary> | ||||
|     public string SocketId { get; set; } | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     public static ModbusAddress ParseFrom(string address, byte station) | ||||
|     { | ||||
|         ModbusAddress modbusAddress = new() | ||||
|         { | ||||
|             Station = station | ||||
|         }; | ||||
|         return ParseFrom(address, modbusAddress); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     public static ModbusAddress ParseFrom(string address, ModbusAddress modbusAddress = null) | ||||
|     { | ||||
|         modbusAddress ??= new(); | ||||
|         if (address.IndexOf(';') < 0) | ||||
|         { | ||||
|             Address(address); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             string[] strArray = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); | ||||
|             for (int index = 0; index < strArray.Length; ++index) | ||||
|             { | ||||
|                 if (strArray[index].ToUpper().StartsWith("S=")) | ||||
|                 { | ||||
|                     if (Convert.ToInt16(strArray[index].Substring(2)) > 0) | ||||
|                         modbusAddress.Station = byte.Parse(strArray[index].Substring(2)); | ||||
|                 } | ||||
|                 else if (strArray[index].ToUpper().StartsWith("W=")) | ||||
|                 { | ||||
|                     if (Convert.ToInt16(strArray[index].Substring(2)) > 0) | ||||
|                         modbusAddress.WriteFunction = byte.Parse(strArray[index].Substring(2)); | ||||
|                 } | ||||
|                 else if (strArray[index].ToUpper().StartsWith("ID=")) | ||||
|                 { | ||||
|                     modbusAddress.SocketId = strArray[index].Substring(3); | ||||
|                 } | ||||
|                 else if (!strArray[index].Contains("=")) | ||||
|                 { | ||||
|                     Address(strArray[index]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return modbusAddress; | ||||
|  | ||||
|         void Address(string address) | ||||
|         { | ||||
|             var readF = ushort.Parse(address.Substring(0, 1)); | ||||
|             if (readF > 4) | ||||
|                 throw new("功能码错误"); | ||||
|             switch (readF) | ||||
|             { | ||||
|                 case 0: | ||||
|                     modbusAddress.ReadFunction = 1; | ||||
|                     break; | ||||
|                 case 1: | ||||
|                     modbusAddress.ReadFunction = 2; | ||||
|                     break; | ||||
|                 case 3: | ||||
|                     modbusAddress.ReadFunction = 4; | ||||
|                     break; | ||||
|                 case 4: | ||||
|                     modbusAddress.ReadFunction = 3; | ||||
|                     break; | ||||
|             } | ||||
|             modbusAddress.Address = (double.Parse(address.Substring(1)) - 1).ToString(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         StringBuilder stringGeter = new(); | ||||
|         if (Station > 0) | ||||
|         { | ||||
|             stringGeter.Append("s=" + Station.ToString() + ";"); | ||||
|         } | ||||
|         if (WriteFunction > 0) | ||||
|         { | ||||
|             stringGeter.Append("w=" + WriteFunction.ToString() + ";"); | ||||
|         } | ||||
|         if (!string.IsNullOrEmpty(SocketId)) | ||||
|         { | ||||
|             stringGeter.Append("id=" + SocketId + ";"); | ||||
|         } | ||||
|         stringGeter.Append(GetFunctionString(ReadFunction) + (AddressStart + 1).ToString()); | ||||
|         return stringGeter.ToString(); | ||||
|     } | ||||
|  | ||||
|     private string GetFunctionString(int readF) | ||||
|     { | ||||
|         return readF switch | ||||
|         { | ||||
|             1 => "0", | ||||
|             2 => "1", | ||||
|             3 => "4", | ||||
|             4 => "3", | ||||
|             _ => "4", | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @@ -1,334 +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.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Bool; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| internal class ModbusHelper | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 添加Crc16 | ||||
|     /// </summary> | ||||
|     internal static byte[] AddCrc(byte[] command) | ||||
|     { | ||||
|         return EasyCRC16.CRC16(command); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 添加ModbusTcp报文头 | ||||
|     /// </summary> | ||||
|     internal static byte[] AddModbusTcpHead(byte[] modbus, ushort id) | ||||
|     { | ||||
|         byte[] tcp = new byte[modbus.Length + 6]; | ||||
|         tcp[0] = BitConverter.GetBytes(id)[1]; | ||||
|         tcp[1] = BitConverter.GetBytes(id)[0]; | ||||
|         tcp[4] = BitConverter.GetBytes(modbus.Length)[1]; | ||||
|         tcp[5] = BitConverter.GetBytes(modbus.Length)[0]; | ||||
|         modbus.CopyTo(tcp, 6); | ||||
|         return tcp; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// modbus地址格式说明 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     internal static string GetAddressDescription() | ||||
|     { | ||||
|         StringBuilder stringBuilder = new(); | ||||
|         stringBuilder.AppendLine("Modbus寄存器"); | ||||
|         stringBuilder.AppendLine("线圈寄存器使用从 00001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("离散输入寄存器使用从 10001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("输入寄存器使用从 30001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("保持寄存器使用从 40001 开始的地址编号。"); | ||||
|         stringBuilder.AppendLine("举例:"); | ||||
|         stringBuilder.AppendLine("40001=>保持寄存器第一个寄存器"); | ||||
|         stringBuilder.AppendLine("额外格式:"); | ||||
|         stringBuilder.AppendLine("设备站号 ,比如40001;s=2; ,代表设备地址为2的保持寄存器第一个寄存器"); | ||||
|         stringBuilder.AppendLine("写入功能码 ,比如40001;w=16; ,代表保持寄存器第一个寄存器,写入值时采用0x10功能码,而不是默认的0x06功能码"); | ||||
|         return stringBuilder.ToString(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 通过错误码来获取到对应的文本消息 | ||||
|     /// </summary> | ||||
|     internal static string GetDescriptionByErrorCode(byte code) | ||||
|     { | ||||
|         return code switch | ||||
|         { | ||||
|             1 => "不支持的功能码", | ||||
|             2 => "读取寄存器越界", | ||||
|             3 => "读取长度超限", | ||||
|             4 => "读写异常", | ||||
|             _ => "未知错误", | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取modbus数据区内容,返回数据需去除Crc和报文头,例如:01 03 02 00 01,发送数据需报文头 | ||||
|     /// </summary> | ||||
|     /// <param name="send">发送数据</param> | ||||
|     /// <param name="response">返回数据</param> | ||||
|     /// <returns></returns> | ||||
|     internal static OperResult<byte[], FilterResult> GetModbusData(byte[] send, byte[] response) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             if (response.Length < 3) | ||||
|                 return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|  | ||||
|             if (response[1] >= 0x80)//错误码 | ||||
|                 return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success }; | ||||
|             if (response[1] <= 0x05) | ||||
|             { | ||||
|                 if ((response.Length < response[2] + 3)) | ||||
|                     return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if ((response.Length < 6)) | ||||
|                     return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|             } | ||||
|  | ||||
|             if (send.Length == 0) | ||||
|             { | ||||
|                 var result = OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success); | ||||
|                 result.Message = "接收数据正确,但主机并没有主动请求数据"; | ||||
|                 return result; | ||||
|             } | ||||
|             if (send[0] != response[0]) | ||||
|                 return new OperResult<byte[], FilterResult>(string.Format("站号不一致", send[0], response[0])) { Content2 = FilterResult.Success }; | ||||
|             if (send[1] != response[1]) | ||||
|                 return new OperResult<byte[], FilterResult>() { Message = "功能码不一致", Content2 = FilterResult.Success }; | ||||
|             return OperResult.CreateSuccessResult(GenericExtensions.ArrayRemoveBegin(response, 3), FilterResult.Success); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[], FilterResult>(ex.Message) { Content2 = FilterResult.Success }; | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 去除Crc,返回modbus数据区 | ||||
|     /// </summary> | ||||
|     /// <param name="send"></param> | ||||
|     /// <param name="response"></param> | ||||
|     /// <param name="crcCheck"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static OperResult<byte[], FilterResult> GetModbusRtuData(byte[] send, byte[] response, bool crcCheck = true) | ||||
|     { | ||||
|         if (response.Length < 3) | ||||
|             return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|         if (response[1] >= 0x80)//错误码 | ||||
|             return new OperResult<byte[], FilterResult>(GetDescriptionByErrorCode(response[2])) { Content2 = FilterResult.Success }; | ||||
|         if (response[1] <= 0x05) | ||||
|         { | ||||
|             if ((response.Length < response[2] + 5)) | ||||
|                 return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if ((response.Length < 8)) | ||||
|                 return new OperResult<byte[], FilterResult>("数据长度不足" + response.ToHexString()) { Content2 = FilterResult.Cache }; | ||||
|  | ||||
|         } | ||||
|  | ||||
|  | ||||
|         var data = response.SelectMiddle(0, response[2] != 0 ? response[2] + 5 : 8); | ||||
|         if (crcCheck && !EasyCRC16.CheckCRC16(data)) | ||||
|             return new OperResult<byte[], FilterResult>("Crc校验失败" + DataTransUtil.ByteToHexString(data, ' ')) { Content2 = FilterResult.Success }; | ||||
|         return GetModbusData(send, data.RemoveLast(2)); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取读取报文 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetReadModbusCommand(string address, int length, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, station); | ||||
|             return OperResult.CreateSuccessResult(GetReadModbusCommand(mAddress, length)); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取写入布尔量报文,根据地址识别功能码 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool[] values, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, station); | ||||
|  | ||||
|             //功能码或实际长度 | ||||
|             if (values?.Length > 1 || mAddress.WriteFunction == 15) | ||||
|                 return GetWriteBoolModbusCommand(mAddress, values, values.Length); | ||||
|             else | ||||
|                 return GetWriteBoolModbusCommand(address, values[0], station); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取写入字报文,根据地址识别功能码 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetWriteModbusCommand(string address, byte[] value, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, station); | ||||
|  | ||||
|             //功能码或实际长度 | ||||
|             if (value?.Length > 2 || mAddress.WriteFunction == 16) | ||||
|                 return OperResult.CreateSuccessResult(GetWriteModbusCommand(mAddress, value)); | ||||
|             else | ||||
|                 return OperResult.CreateSuccessResult(GetWriteOneModbusCommand(mAddress, value)); | ||||
|  | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取读取报文 | ||||
|     /// </summary> | ||||
|     internal static byte[] GetReadModbusCommand(ModbusAddress mAddress, int length) | ||||
|     { | ||||
|         byte[] array = new byte[6] | ||||
|         { | ||||
|         (byte) mAddress.Station, | ||||
|         (byte) mAddress.ReadFunction, | ||||
|         BitConverter.GetBytes(mAddress.AddressStart)[1], | ||||
|         BitConverter.GetBytes(mAddress.AddressStart)[0], | ||||
|         BitConverter.GetBytes(length)[1], | ||||
|         BitConverter.GetBytes(length)[0] | ||||
|         }; | ||||
|         return array; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取05写入布尔量报文 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetWriteBoolModbusCommand(string address, bool value, byte station) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             if (address.IndexOf('.') <= 0) | ||||
|             { | ||||
|                 var mAddress = ModbusAddress.ParseFrom(address, station); | ||||
|  | ||||
|                 return OperResult.CreateSuccessResult(GetWriteBoolModbusCommand(mAddress, value)); | ||||
|             } | ||||
|             return new("不支持写入字寄存器的某一位"); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取05写入布尔量报文 | ||||
|     /// </summary> | ||||
|     private static byte[] GetWriteBoolModbusCommand(ModbusAddress mAddress, bool value) | ||||
|     { | ||||
|         byte[] array = new byte[6] | ||||
|         { | ||||
|     (byte) mAddress.Station, | ||||
|     (byte)5, | ||||
|     BitConverter.GetBytes(mAddress.AddressStart)[1], | ||||
|     BitConverter.GetBytes(mAddress.AddressStart)[0], | ||||
|      0, | ||||
|      0 | ||||
|         }; | ||||
|         if (value) | ||||
|         { | ||||
|             array[4] = 0xFF; | ||||
|             array[5] = 0; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             array[4] = 0; | ||||
|             array[5] = 0; | ||||
|         } | ||||
|         return array; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取15写入布尔量报文 | ||||
|     /// </summary> | ||||
|     internal static OperResult<byte[]> GetWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values, int length) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             byte[] numArray1 = values.BoolArrayToByte(); | ||||
|             byte[] numArray2 = new byte[7 + numArray1.Length]; | ||||
|             numArray2[0] = (byte)mAddress.Station; | ||||
|             numArray2[1] = (byte)15; | ||||
|             numArray2[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|             numArray2[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|             numArray2[4] = (byte)(length / 256); | ||||
|             numArray2[5] = (byte)(length % 256); | ||||
|             numArray2[6] = (byte)numArray1.Length; | ||||
|             numArray1.CopyTo(numArray2, 7); | ||||
|             return OperResult.CreateSuccessResult(numArray2); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取16写入字报文 | ||||
|     /// </summary> | ||||
|     internal static byte[] GetWriteModbusCommand(ModbusAddress mAddress, byte[] values) | ||||
|     { | ||||
|         byte[] numArray = new byte[7 + values.Length]; | ||||
|         numArray[0] = (byte)mAddress.Station; | ||||
|         numArray[1] = (byte)16; | ||||
|         numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|         numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|         numArray[4] = (byte)(values.Length / 2 / 256); | ||||
|         numArray[5] = (byte)(values.Length / 2 % 256); | ||||
|         numArray[6] = (byte)values.Length; | ||||
|         values.CopyTo(numArray, 7); | ||||
|         return numArray; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取6写入字报文 | ||||
|     /// </summary> | ||||
|     internal static byte[] GetWriteOneModbusCommand(ModbusAddress mAddress, byte[] values) | ||||
|     { | ||||
|         byte[] numArray = new byte[4 + values.Length]; | ||||
|         numArray[0] = (byte)mAddress.Station; | ||||
|         numArray[1] = (byte)6; | ||||
|         numArray[2] = BitConverter.GetBytes(mAddress.AddressStart)[1]; | ||||
|         numArray[3] = BitConverter.GetBytes(mAddress.AddressStart)[0]; | ||||
|         values.CopyTo(numArray, 4); | ||||
|         return numArray; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,191 +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.Adapter.Modbus; | ||||
| /// <summary> | ||||
| /// ModbusRtu | ||||
| /// </summary> | ||||
| public class ModbusRtu : ReadWriteDevicesSerialSessionBase | ||||
| { | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ModbusRtu | ||||
|     /// </summary> | ||||
|     /// <param name="serialSession"></param> | ||||
|     public ModbusRtu(SerialSession serialSession) : base(serialSession) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Crc校验 | ||||
|     /// </summary> | ||||
|     [Description("Crc校验")] | ||||
|     public bool Crc16CheckEnable { get; set; } = true; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 站号 | ||||
|     /// </summary> | ||||
|     [Description("站号")] | ||||
|     public byte Station { get; set; } = 1; | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() | ||||
|     { | ||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) | ||||
|     { | ||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter(object socketClient = null) | ||||
|     { | ||||
|         ModbusRtuDataHandleAdapter dataHandleAdapter = new() | ||||
|         { | ||||
|             Crc16CheckEnable = Crc16CheckEnable, | ||||
|             CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) | ||||
|         }; | ||||
|         SerialSession.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             if (FrameTime != 0) | ||||
|                 Thread.Sleep(FrameTime); | ||||
|             var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             await Task.Delay(FrameTime, cancellationToken); | ||||
|             var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,85 +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.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// Rtu适配器 | ||||
| /// </summary> | ||||
| public class ModbusRtuDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusRtuMessage> | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 检测CRC | ||||
|     /// </summary> | ||||
|     public bool Crc16CheckEnable { get; set; } = true; | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="command"></param> | ||||
|     /// <returns></returns> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return ModbusHelper.AddCrc(command); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ModbusRtuMessage GetInstance() | ||||
|     { | ||||
|         return new ModbusRtuMessage(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(ModbusRtuMessage request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         //链路干扰时需剔除前缀中的多于字节,初步按站号+功能码找寻初始字节 | ||||
|         if (send?.Length > 0) | ||||
|         { | ||||
|             int index = -1; | ||||
|             for (int i = 0; i < response.Length - 1; i++) | ||||
|             { | ||||
|                 if (response[i] == send[0] && (response[i + 1] == send[1] || response[i + 1] == (send[1] + 0x80))) | ||||
|                 { | ||||
|                     index = i; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (index >= 0) | ||||
|             { | ||||
|                 response = response.RemoveBegin(index); | ||||
|             } | ||||
|  | ||||
|             //理想状态检测 | ||||
|             var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable); | ||||
|             if (result.IsSuccess) | ||||
|             { | ||||
|                 request.ErrorCode = result.ErrorCode; | ||||
|                 request.Message = result.Message; | ||||
|                 request.Content = result.Content; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 request.ErrorCode = result.ErrorCode; | ||||
|                 request.Message = result.Message; | ||||
|             } | ||||
|             return result.Content2; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return FilterResult.Success; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,34 +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.Adapter.Modbus; | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public class ModbusRtuMessage : MessageBase, IMessage | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public override int HeadBytesLength => -1; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override bool CheckHeadBytes(byte[] head) | ||||
|     { | ||||
|         BodyLength = -1; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void SendBytesThen() | ||||
|     { | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,185 +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.Adapter.Modbus; | ||||
| /// <inheritdoc/> | ||||
| public class ModbusRtuOverTcp : ReadWriteDevicesTcpClientBase | ||||
| { | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ModbusRtuOverTcp(TcpClient tcpClient) : base(tcpClient) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Crc校验 | ||||
|     /// </summary> | ||||
|     [Description("Crc校验")] | ||||
|     public bool Crc16CheckEnable { get; set; } = true; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 站号 | ||||
|     /// </summary> | ||||
|     [Description("站号")] | ||||
|     public byte Station { get; set; } = 1; | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() | ||||
|     { | ||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) | ||||
|     { | ||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter(object socketClient = null) | ||||
|     { | ||||
|         ModbusRtuDataHandleAdapter dataHandleAdapter = new() | ||||
|         { | ||||
|             Crc16CheckEnable = Crc16CheckEnable, | ||||
|             CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) | ||||
|         }; | ||||
|         TcpClient.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             if (FrameTime != 0) | ||||
|                 Thread.Sleep(FrameTime); | ||||
|             var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             await Task.Delay(FrameTime, cancellationToken); | ||||
|             var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,184 +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.Adapter.Modbus; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class ModbusRtuOverUdp : ReadWriteDevicesUdpSessionBase | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public ModbusRtuOverUdp(UdpSession udpSession) : base(udpSession) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Crc校验 | ||||
|     /// </summary> | ||||
|     [Description("Crc校验")] | ||||
|     public bool Crc16CheckEnable { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 站号 | ||||
|     /// </summary> | ||||
|     [Description("站号")] | ||||
|     public byte Station { get; set; } = 1; | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() | ||||
|     { | ||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter(object socketClient = null) | ||||
|     { | ||||
|         ModbusRtuOverUdpDataHandleAdapter dataHandleAdapter = new() | ||||
|         { | ||||
|             Crc16CheckEnable = Crc16CheckEnable, | ||||
|         }; | ||||
|         UdpSession.Config.SetUdpDataHandlingAdapter(() => | ||||
|         { | ||||
|             return dataHandleAdapter; | ||||
|         }); | ||||
|         UdpSession.Setup(UdpSession.Config); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) | ||||
|     { | ||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             if (FrameTime != 0) | ||||
|                 Thread.Sleep(FrameTime); | ||||
|             var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             await Task.Delay(FrameTime, cancellationToken); | ||||
|             var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,43 +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.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public class ModbusRtuOverUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAdapter<ModbusRtuMessage> | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 检测CRC | ||||
|     /// </summary> | ||||
|     public bool Crc16CheckEnable { get; set; } = true; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return ModbusHelper.AddCrc(command); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ModbusRtuMessage GetInstance() | ||||
|     { | ||||
|         return new ModbusRtuMessage(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response) | ||||
|     { | ||||
|         var result = ModbusHelper.GetModbusRtuData(send, response, Crc16CheckEnable); | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| @@ -1,420 +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 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,141 +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.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class ModbusSerialServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusSerialServerMessage> | ||||
| { | ||||
|     private readonly ThingsGatewayBitConverter ThingsGatewayBitConverter = new(EndianType.Big); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="command"></param> | ||||
|     /// <returns></returns> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return ModbusHelper.AddCrc(command); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取modbus写入数据区内容 | ||||
|     /// </summary> | ||||
|     /// <param name="response">返回数据</param> | ||||
|     /// <returns></returns> | ||||
|     internal OperResult<byte[]> GetModbusData(byte[] response) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var func = ThingsGatewayBitConverter.ToByte(response, 1); | ||||
|             if (func == 1 || func == 2 || func == 3 || func == 4 || func == 5 || func == 6) | ||||
|             { | ||||
|                 if (response.Length == 6) | ||||
|                     return OperResult.CreateSuccessResult(response); | ||||
|             } | ||||
|             else if (func == 15 || func == 16) | ||||
|             { | ||||
|                 var length = ThingsGatewayBitConverter.ToByte(response, 6); | ||||
|                 if (response.Length == 7 + length) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(response); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return new OperResult<byte[]>() { Message = $"数据长度{response.Length}错误" }; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ModbusSerialServerMessage GetInstance() | ||||
|     { | ||||
|         return new ModbusSerialServerMessage(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(ModbusSerialServerMessage request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         var result1 = ModbusHelper.GetModbusRtuData(new byte[0], response, true); | ||||
|         if (result1.IsSuccess) | ||||
|         { | ||||
|             var result = GetModbusData(response.RemoveLast(2)); | ||||
|             if (result.IsSuccess) | ||||
|             { | ||||
|                 //解析01 03 00 00 00 0A | ||||
|                 var station = ThingsGatewayBitConverter.ToByte(response, 0); | ||||
|                 var function = ThingsGatewayBitConverter.ToByte(response, 1); | ||||
|                 int addressStart = ThingsGatewayBitConverter.ToInt16(response, 2); | ||||
|                 if (addressStart == -1) | ||||
|                 { | ||||
|                     addressStart = 65535; | ||||
|                 } | ||||
|                 if (function > 4) | ||||
|                 { | ||||
|                     if (function > 6) | ||||
|                     { | ||||
|                         request.CurModbusAddress = new ModbusAddress() | ||||
|                         { | ||||
|                             Station = station, | ||||
|                             Address = addressStart.ToString(), | ||||
|                             WriteFunction = function, | ||||
|                             ReadFunction = (byte)(function == 16 ? 3 : function == 15 ? 1 : 3), | ||||
|                         }; | ||||
|                         request.Length = ThingsGatewayBitConverter.ToByte(response, 5); | ||||
|                         request.Content = result.Content.RemoveBegin(7); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         request.CurModbusAddress = new ModbusAddress() | ||||
|                         { | ||||
|                             Station = station, | ||||
|                             Address = addressStart.ToString(), | ||||
|                             WriteFunction = function, | ||||
|                             ReadFunction = (byte)(function == 6 ? 3 : function == 5 ? 1 : 3), | ||||
|                         }; | ||||
|                         request.Length = 1; | ||||
|                         request.Content = result.Content.RemoveBegin(4); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     request.CurModbusAddress = new ModbusAddress() | ||||
|                     { | ||||
|                         Station = station, | ||||
|                         Address = addressStart.ToString(), | ||||
|                         ReadFunction = function, | ||||
|                     }; | ||||
|                     request.Length = ThingsGatewayBitConverter.ToByte(response, 5); | ||||
|                 } | ||||
|                 request.ErrorCode = result.ErrorCode; | ||||
|                 request.Message = result.Message; | ||||
|                 return FilterResult.Success; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 request.ErrorCode = result.ErrorCode; | ||||
|                 request.Message = result.Message; | ||||
|                 return FilterResult.Cache; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return result1.Content2; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,43 +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.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public class ModbusSerialServerMessage : MessageBase, IMessage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 当前关联的地址 | ||||
|     /// </summary> | ||||
|     public ModbusAddress CurModbusAddress { get; set; } | ||||
|     /// <summary> | ||||
|     /// 当前读写的数据长度 | ||||
|     /// </summary> | ||||
|     public int Length { get; set; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override int HeadBytesLength => -1; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override bool CheckHeadBytes(byte[] head) | ||||
|     { | ||||
|         BodyLength = -1; | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override void SendBytesThen() | ||||
|     { | ||||
|     } | ||||
| } | ||||
| @@ -1,184 +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.Adapter.Modbus; | ||||
| /// <inheritdoc/> | ||||
| public class ModbusTcp : ReadWriteDevicesTcpClientBase | ||||
| { | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ModbusTcp(TcpClient tcpClient) : base(tcpClient) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 检测事务标识符 | ||||
|     /// </summary> | ||||
|     [Description("检测事务标识符")] | ||||
|     public bool IsCheckMessageId { get; set; } | ||||
|     /// <summary> | ||||
|     /// 站号 | ||||
|     /// </summary> | ||||
|     [Description("站号")] | ||||
|     public byte Station { get; set; } = 1; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() | ||||
|     { | ||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) | ||||
|     { | ||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             var data = SendThenReturn(commandResult, cancellationToken); | ||||
|             return data; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|  | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             var data = await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|             return data; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter(object socketClient = null) | ||||
|     { | ||||
|         ModbusTcpDataHandleAdapter dataHandleAdapter = new() | ||||
|         { | ||||
|             IsCheckMessageId = IsCheckMessageId, | ||||
|             CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) | ||||
|         }; | ||||
|         TcpClient.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             if (FrameTime != 0) | ||||
|                 Thread.Sleep(FrameTime); | ||||
|             var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             await Task.Delay(FrameTime, cancellationToken); | ||||
|             var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,70 +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.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// ModbusTcpDataHandleAdapter | ||||
| /// </summary> | ||||
| public class ModbusTcpDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusTcpMessage> | ||||
| { | ||||
|     private readonly EasyIncrementCount easyIncrementCount = new(ushort.MaxValue); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 检测事务标识符 | ||||
|     /// </summary> | ||||
|     public bool IsCheckMessageId | ||||
|     { | ||||
|         get | ||||
|         { | ||||
|             return Request?.IsCheckMessageId ?? false; | ||||
|         } | ||||
|         set | ||||
|         { | ||||
|             Request.IsCheckMessageId = value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return ModbusHelper.AddModbusTcpHead(command, (ushort)easyIncrementCount.GetCurrentValue()); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ModbusTcpMessage GetInstance() | ||||
|     { | ||||
|         return new ModbusTcpMessage(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(ModbusTcpMessage request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         //理想状态检测 | ||||
|         var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6)); | ||||
|         if (result.IsSuccess) | ||||
|         { | ||||
|             request.ErrorCode = result.ErrorCode; | ||||
|             request.Message = result.Message; | ||||
|             request.Content = result.Content; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             request.ErrorCode = result.ErrorCode; | ||||
|             request.Message = result.Message; | ||||
|         } | ||||
|         return result.Content2; | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -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.Adapter.Modbus; | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public class ModbusTcpMessage : MessageBase, IMessage | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public override int HeadBytesLength => 6; | ||||
|     /// <summary> | ||||
|     /// 检测事务标识符 | ||||
|     /// </summary> | ||||
|     public bool IsCheckMessageId { get; set; } = false; | ||||
|     /// <inheritdoc/> | ||||
|     public override bool CheckHeadBytes(byte[] head) | ||||
|     { | ||||
|         if (head == null || head.Length <= 0) return false; | ||||
|         HeadBytes = head; | ||||
|  | ||||
|         int num = (HeadBytes[4] * 256) + HeadBytes[5]; | ||||
|         BodyLength = num; | ||||
|  | ||||
|         if (!IsCheckMessageId) | ||||
|             return true; | ||||
|         else | ||||
|             return SendBytes[0] == HeadBytes[0] && SendBytes[1] == HeadBytes[1] && HeadBytes[2] == 0 && HeadBytes[3] == 0; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,258 +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.Adapter.Modbus; | ||||
| /// <inheritdoc/> | ||||
| public class ModbusTcpDtu : ReadWriteDevicesTcpServerBase | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public ModbusTcpDtu(TcpService tcpService) : base(tcpService) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|         ModbusTcpDtuPlugin modbusTcpSalvePlugin = new ModbusTcpDtuPlugin(); | ||||
|         tcpService.Config.ConfigurePlugins(a => | ||||
|          { | ||||
|              a.Add(modbusTcpSalvePlugin); | ||||
|          }); | ||||
|         tcpService.Setup(tcpService.Config); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 检测事务标识符 | ||||
|     /// </summary> | ||||
|     [Description("检测事务标识符")] | ||||
|     public bool IsCheckMessageId { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 站号 | ||||
|     /// </summary> | ||||
|     [Description("站号")] | ||||
|     public byte Station { get; set; } = 1; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() | ||||
|     { | ||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) | ||||
|     { | ||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, Station); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return SendThenReturn(mAddress.SocketId, commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, Station); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return await SendThenReturnAsync(mAddress.SocketId, commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="client"></param> | ||||
|     /// <param name="e"></param> | ||||
|     protected override void Connecting(SocketClient client, ConnectingEventArgs e) | ||||
|     { | ||||
|         Logger?.Debug(client.IP + ":" + client.Port + "正在连接"); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter(object socketClient = null) | ||||
|     { | ||||
|         if (socketClient is SocketClient client) | ||||
|         { | ||||
|             ModbusTcpDataHandleAdapter dataHandleAdapter = new() | ||||
|             { | ||||
|                 IsCheckMessageId = IsCheckMessageId, | ||||
|                 CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) | ||||
|             }; | ||||
|             client.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             foreach (var item in TcpService.GetClients()) | ||||
|             { | ||||
|                 ModbusTcpDataHandleAdapter dataHandleAdapter = new() | ||||
|                 { | ||||
|                     IsCheckMessageId = IsCheckMessageId, | ||||
|                     CacheTimeout = TimeSpan.FromMilliseconds(CacheTimeout) | ||||
|                 }; | ||||
|                 item.SetDataHandlingAdapter(dataHandleAdapter); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, Station); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(mAddress.SocketId, commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, Station); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(mAddress.SocketId, commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, Station); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(mAddress.SocketId, commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var mAddress = ModbusAddress.ParseFrom(address, Station); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(mAddress.SocketId, commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private OperResult<byte[]> SendThenReturn(string id, OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             if (TcpService.TryGetSocketClient($"ID={id}", out var client)) | ||||
|             { | ||||
|                 SetDataAdapter(client); | ||||
|  | ||||
|                 var item = commandResult.Content; | ||||
|                 if (FrameTime != 0) | ||||
|                     Thread.Sleep(FrameTime); | ||||
|                 var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true }); | ||||
|                 var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|                 return (MessageBase)result.RequestInfo; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return new OperResult<byte[]>("客户端未连接"); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return commandResult; | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult<byte[]>> SendThenReturnAsync(string id, OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             if (TcpService.TryGetSocketClient($"ID={id}", out var client)) | ||||
|             { | ||||
|                 SetDataAdapter(client); | ||||
|  | ||||
|                 var item = commandResult.Content; | ||||
|                 await Task.Delay(FrameTime, cancellationToken); | ||||
|                 var WaitingClientEx = client.GetWaitingClientEx(new() { BreakTrigger = true }); | ||||
|                 var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|                 return (MessageBase)result.RequestInfo; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return new OperResult<byte[]>("客户端未连接"); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return commandResult; | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     internal class ModbusTcpDtuPlugin : PluginBase, ITcpReceivingPlugin | ||||
|     { | ||||
|         public Task OnTcpReceiving(ITcpClientBase client, ByteBlockEventArgs e) | ||||
|         { | ||||
|             if (client is ISocketClient socket) | ||||
|             { | ||||
|                 if (!socket.Id.StartsWith("ID=")) | ||||
|                 { | ||||
|                     ByteBlock byteBlock = e.ByteBlock; | ||||
|                     var id = $"ID={byteBlock.ToArray().ToHexString()}"; | ||||
|                     socket.ResetId(id); | ||||
|                 } | ||||
|             } | ||||
|             return e.InvokeNext();//如果本插件无法处理当前数据,请将数据转至下一个插件。 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,440 +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.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,132 +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.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class ModbusTcpServerDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<ModbusTcpServerMessage> | ||||
| { | ||||
|     private readonly ThingsGatewayBitConverter ThingsGatewayBitConverter = new(EndianType.Big); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <param name="command"></param> | ||||
|     /// <returns></returns> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return command; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取modbus写入数据区内容 | ||||
|     /// </summary> | ||||
|     /// <param name="response">返回数据</param> | ||||
|     /// <returns></returns> | ||||
|     internal OperResult<byte[]> GetModbusData(byte[] response) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var func = ThingsGatewayBitConverter.ToByte(response, 1); | ||||
|             if (func == 1 || func == 2 || func == 3 || func == 4 || func == 5 || func == 6) | ||||
|             { | ||||
|                 if (response.Length == 6) | ||||
|                     return OperResult.CreateSuccessResult(response); | ||||
|             } | ||||
|             else if (func == 15 || func == 16) | ||||
|             { | ||||
|                 var length = ThingsGatewayBitConverter.ToByte(response, 6); | ||||
|                 if (response.Length == 7 + length) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(response); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return new OperResult<byte[]>() { Message = $"数据长度{response.Length}错误" }; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ModbusTcpServerMessage GetInstance() | ||||
|     { | ||||
|         return new ModbusTcpServerMessage(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(ModbusTcpServerMessage request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         var result = GetModbusData(response.RemoveBegin(6)); | ||||
|         if (result.IsSuccess) | ||||
|         { | ||||
|             //解析01 03 00 00 00 0A | ||||
|             var station = ThingsGatewayBitConverter.ToByte(response, 6); | ||||
|             var function = ThingsGatewayBitConverter.ToByte(response, 7); | ||||
|             int addressStart = ThingsGatewayBitConverter.ToInt16(response, 8); | ||||
|             if (addressStart == -1) | ||||
|             { | ||||
|                 addressStart = 65535; | ||||
|             } | ||||
|             if (function > 4) | ||||
|             { | ||||
|                 if (function > 6) | ||||
|                 { | ||||
|                     request.CurModbusAddress = new ModbusAddress() | ||||
|                     { | ||||
|                         Station = station, | ||||
|                         Address = addressStart.ToString(), | ||||
|                         WriteFunction = function, | ||||
|                         ReadFunction = (byte)(function == 16 ? 3 : function == 15 ? 1 : 3), | ||||
|                     }; | ||||
|                     request.Length = ThingsGatewayBitConverter.ToByte(response, 11); | ||||
|                     request.Content = result.Content.RemoveBegin(7); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     request.CurModbusAddress = new ModbusAddress() | ||||
|                     { | ||||
|                         Station = station, | ||||
|                         Address = addressStart.ToString(), | ||||
|                         WriteFunction = function, | ||||
|                         ReadFunction = (byte)(function == 6 ? 3 : function == 5 ? 1 : 3), | ||||
|                     }; | ||||
|                     request.Length = 1; | ||||
|                     request.Content = result.Content.RemoveBegin(4); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 request.CurModbusAddress = new ModbusAddress() | ||||
|                 { | ||||
|                     Station = station, | ||||
|                     Address = addressStart.ToString(), | ||||
|                     ReadFunction = function, | ||||
|                 }; | ||||
|                 request.Length = ThingsGatewayBitConverter.ToByte(response, 11); | ||||
|             } | ||||
|             request.ErrorCode = result.ErrorCode; | ||||
|             request.Message = result.Message; | ||||
|             return FilterResult.Success; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             request.ErrorCode = result.ErrorCode; | ||||
|             request.Message = result.Message; | ||||
|             return FilterResult.Cache; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,43 +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.Adapter.Modbus | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public class ModbusTcpServerMessage : MessageBase, IMessage | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 当前关联的地址 | ||||
|         /// </summary> | ||||
|         public ModbusAddress CurModbusAddress { get; set; } | ||||
|         /// <summary> | ||||
|         /// 当前读写的数据长度 | ||||
|         /// </summary> | ||||
|         public int Length { get; set; } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override int HeadBytesLength => 6; | ||||
|         /// <inheritdoc/> | ||||
|         public override bool CheckHeadBytes(byte[] head) | ||||
|         { | ||||
|             if (head == null || head.Length != 6) return false; | ||||
|             HeadBytes = head; | ||||
|  | ||||
|             int num = (HeadBytes[4] * 256) + HeadBytes[5]; | ||||
|             BodyLength = num; | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,187 +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.Adapter.Modbus; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class ModbusUdp : ReadWriteDevicesUdpSessionBase | ||||
| { | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public ModbusUdp(UdpSession udpSession) : base(udpSession) | ||||
|     { | ||||
|         ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|         RegisterByteLength = 2; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 检测事务标识符 | ||||
|     /// </summary> | ||||
|     [Description("检测事务标识符")] | ||||
|     public bool IsCheckMessageId { get; set; } | ||||
|     /// <summary> | ||||
|     /// 站号 | ||||
|     /// </summary> | ||||
|     [Description("站号")] | ||||
|     public byte Station { get; set; } = 1; | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack) | ||||
|     { | ||||
|         return PackHelper.LoadSourceRead<T, T2>(this, deviceVariables, maxPack); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string GetAddressDescription() | ||||
|     { | ||||
|         return base.GetAddressDescription() + Environment.NewLine + ModbusHelper.GetAddressDescription(); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult<byte[]> Read(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetReadModbusCommand(address, length, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<byte[]>(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void SetDataAdapter(object socketClient = null) | ||||
|     { | ||||
|         ModbusUdpDataHandleAdapter dataHandleAdapter = new() | ||||
|         { | ||||
|             IsCheckMessageId = IsCheckMessageId | ||||
|         }; | ||||
|         UdpSession.Config.SetUdpDataHandlingAdapter(() => | ||||
|         { | ||||
|             return dataHandleAdapter; | ||||
|         }); | ||||
|         UdpSession.Setup(UdpSession.Config); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Connect(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return SendThenReturn(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await ConnectAsync(cancellationToken); | ||||
|             var commandResult = ModbusHelper.GetWriteBoolModbusCommand(address, value, Station); | ||||
|             return await SendThenReturnAsync(commandResult, cancellationToken); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private OperResult<byte[]> SendThenReturn(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             if (FrameTime != 0) | ||||
|                 Thread.Sleep(FrameTime); | ||||
|             var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult<byte[]>> SendThenReturnAsync(OperResult<byte[]> commandResult, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (commandResult.IsSuccess) | ||||
|         { | ||||
|             var item = commandResult.Content; | ||||
|             await Task.Delay(FrameTime, cancellationToken); | ||||
|             var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|             return (MessageBase)result.RequestInfo; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new OperResult<byte[]>(commandResult.Message); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,56 +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.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public class ModbusUdpDataHandleAdapter : ReadWriteDevicesUdpDataHandleAdapter<ModbusTcpMessage> | ||||
| { | ||||
|     private readonly EasyIncrementCount easyIncrementCount = new(ushort.MaxValue); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 检测事务标识符 | ||||
|     /// </summary> | ||||
|     public bool IsCheckMessageId | ||||
|     { | ||||
|         get | ||||
|         { | ||||
|             return Request?.IsCheckMessageId ?? false; | ||||
|         } | ||||
|         set | ||||
|         { | ||||
|             Request.IsCheckMessageId = value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return ModbusHelper.AddModbusTcpHead(command, (ushort)easyIncrementCount.GetCurrentValue()); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override ModbusTcpMessage GetInstance() | ||||
|     { | ||||
|         return new ModbusTcpMessage(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override OperResult<byte[]> UnpackResponse(byte[] send, byte[] response) | ||||
|     { | ||||
|         var result = ModbusHelper.GetModbusData(send.RemoveBegin(6), response.RemoveBegin(6)); | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| @@ -1,169 +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.Extension.Generic; | ||||
| using ThingsGateway.Foundation.Extension.String; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Modbus; | ||||
|  | ||||
| /// <summary> | ||||
| /// PackHelper | ||||
| /// </summary> | ||||
| public class PackHelper | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 打包变量,添加到<see href="deviceVariableSourceReads"></see> | ||||
|     /// </summary> | ||||
|     /// <param name="device"></param> | ||||
|     /// <param name="deviceVariables"></param> | ||||
|     /// <param name="maxPack">最大打包长度</param> | ||||
|     /// <returns></returns> | ||||
|     public static List<T> LoadSourceRead<T, T2>(IReadWrite device, List<T2> deviceVariables, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new() | ||||
|     { | ||||
|         if (deviceVariables == null) | ||||
|             throw new ArgumentNullException(nameof(deviceVariables)); | ||||
|  | ||||
|         var deviceVariableSourceReads = new List<T>(); | ||||
|         var byteConverter = device.ThingsGatewayBitConverter; | ||||
|         //需要先剔除额外信息,比如dataformat等 | ||||
|         foreach (var item in deviceVariables) | ||||
|         { | ||||
|             var address = item.VariableAddress; | ||||
|             IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter); | ||||
|             item.ThingsGatewayBitConverter = transformParameter; | ||||
|             //item.VariableAddress = address; | ||||
|             item.Index = device.GetBitOffset(item.VariableAddress); | ||||
|         } | ||||
|         var deviceVariableRunTimeGroups = deviceVariables.GroupBy(it => it.IntervalTime); | ||||
|         foreach (var group in deviceVariableRunTimeGroups) | ||||
|         { | ||||
|             Dictionary<ModbusAddress, T2> map = group.ToDictionary(it => | ||||
|             { | ||||
|                 var lastLen = it.DataTypeEnum.GetByteLength(); | ||||
|                 if (lastLen <= 0) | ||||
|                 { | ||||
|                     switch (it.DataTypeEnum) | ||||
|                     { | ||||
|                         case DataTypeEnum.String: | ||||
|                             lastLen = it.ThingsGatewayBitConverter.Length == null ? throw new("数据类型为字符串时,必须指定字符串长度,才能进行打包") : it.ThingsGatewayBitConverter.Length.Value; | ||||
|                             break; | ||||
|                         default: | ||||
|                             lastLen = 2; | ||||
|                             break; | ||||
|                     } | ||||
|                 } | ||||
|                 if (it.ThingsGatewayBitConverter.Length != null && it.DataTypeEnum != DataTypeEnum.String) | ||||
|                 { | ||||
|                     lastLen *= it.ThingsGatewayBitConverter.Length.Value; | ||||
|                 } | ||||
|  | ||||
|                 var address = it.VariableAddress; | ||||
|                 if (address.IndexOf('.') > 0) | ||||
|                 { | ||||
|                     var addressSplits = address.SplitDot(); | ||||
|                     address = addressSplits.RemoveLast(1).ArrayToString("."); | ||||
|                 } | ||||
|                 var result = ModbusAddress.ParseFrom(address); | ||||
|                 result.ByteLength = lastLen; | ||||
|                 return result; | ||||
|             }); | ||||
|  | ||||
|             //获取变量的地址 | ||||
|             var modbusAddressList = map.Keys; | ||||
|  | ||||
|             //获取功能码 | ||||
|             var functionCodes = modbusAddressList.Select(t => t.ReadFunction).Distinct(); | ||||
|             foreach (var functionCode in functionCodes) | ||||
|             { | ||||
|                 var modbusAddressSameFunList = modbusAddressList.Where(t => t.ReadFunction == functionCode); | ||||
|                 var stationNumbers = modbusAddressSameFunList.Select(t => t.Station).Distinct(); | ||||
|                 foreach (var stationNumber in stationNumbers) | ||||
|                 { | ||||
|                     var addressList = modbusAddressSameFunList | ||||
|                         .Where(t => t.Station == stationNumber) | ||||
|                         .ToDictionary(t => t, t => map[t]); | ||||
|  | ||||
|                     var tempResult = LoadSourceRead<T, T2>(addressList, functionCode, group.Key, maxPack); | ||||
|                     deviceVariableSourceReads.AddRange(tempResult); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         return deviceVariableSourceReads; | ||||
|     } | ||||
|  | ||||
|     private static List<T> LoadSourceRead<T, T2>(Dictionary<ModbusAddress, T2> addressList, int functionCode, int intervalTime, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new() | ||||
|     { | ||||
|         List<T> sourceReads = new(); | ||||
|         //按地址和长度排序 | ||||
|         var orderByAddressEnd = addressList.Keys.OrderBy(it => it.AddressEnd); | ||||
|         //按地址和长度排序 | ||||
|         var orderByAddressStart = addressList.Keys.OrderBy(it => it.AddressStart); | ||||
|         //地址最小,在循环中更改 | ||||
|         var minAddress = orderByAddressStart.First().AddressStart; | ||||
|         //地址最大 | ||||
|         var maxAddress = orderByAddressStart.Last().AddressStart; | ||||
|  | ||||
|         while (maxAddress >= minAddress) | ||||
|         { | ||||
|             //最大的打包长度 | ||||
|             int readLength = maxPack; | ||||
|             if (functionCode == 1 || functionCode == 2) | ||||
|             { | ||||
|                 readLength = maxPack * 8 * 2; | ||||
|             } | ||||
|  | ||||
|  | ||||
|             //获取当前的一组打包地址信息, | ||||
|             var tempAddressEnd = orderByAddressEnd.Where(t => t.AddressEnd <= minAddress + readLength).ToList(); | ||||
|             //起始地址 | ||||
|             var startAddress = tempAddressEnd.OrderBy(it => it.AddressStart).First(); | ||||
|             //读取寄存器长度 | ||||
|             var sourceLen = tempAddressEnd.Last().AddressEnd - startAddress.AddressStart; | ||||
|  | ||||
|             T sourceRead = new() | ||||
|             { | ||||
|                 TimerTick = new TimerTick(intervalTime), | ||||
|                 //这里只需要根据地址排序的第一个地址,作为实际打包报文中的起始地址 | ||||
|                 VariableAddress = startAddress.ToString(), | ||||
|                 Length = sourceLen | ||||
|             }; | ||||
|             foreach (var item in tempAddressEnd) | ||||
|             { | ||||
|                 var readNode = addressList[item]; | ||||
|                 if ((functionCode == -1 || functionCode == 3 || functionCode == 4) && readNode.DataTypeEnum == DataTypeEnum.Boolean) | ||||
|                 { | ||||
|                     readNode.Index = ((item.AddressStart - startAddress.AddressStart) * 16) + readNode.Index; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (functionCode == 1 || functionCode == 2) | ||||
|                         readNode.Index = item.AddressStart - startAddress.AddressStart + readNode.Index; | ||||
|                     else | ||||
|                         readNode.Index = ((item.AddressStart - startAddress.AddressStart) * 2) + readNode.Index; | ||||
|                 } | ||||
|  | ||||
|                 sourceRead.DeviceVariableRunTimes.Add(readNode); | ||||
|                 addressList.Remove(item); | ||||
|             } | ||||
|  | ||||
|             sourceReads.Add(sourceRead); | ||||
|             if (orderByAddressEnd.Count() > 0) | ||||
|                 minAddress = orderByAddressStart.First().AddressStart; | ||||
|             else | ||||
|                 break; | ||||
|         } | ||||
|         return sourceReads; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,5 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 	<ItemGroup> | ||||
| 		<ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> | ||||
| 	</ItemGroup> | ||||
| </Project> | ||||
| @@ -1,611 +0,0 @@ | ||||
| <?xml version="1.0"?> | ||||
| <doc> | ||||
|     <assembly> | ||||
|         <name>ThingsGateway.Foundation.Adapter.Modbus</name> | ||||
|     </assembly> | ||||
|     <members> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress"> | ||||
|             <summary> | ||||
|             Modbus协议地址 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.#ctor"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.AddressStart"> | ||||
|             <summary> | ||||
|             读取功能码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ReadFunction"> | ||||
|             <summary> | ||||
|             读取功能码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.Station"> | ||||
|             <summary> | ||||
|             站号信息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.WriteFunction"> | ||||
|             <summary> | ||||
|             写入功能码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ByteLength"> | ||||
|             <summary> | ||||
|             打包临时写入,需要读取的字节长度 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.AddressEnd"> | ||||
|             <summary> | ||||
|             读取功能码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.Parse(System.String)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ParseFrom(System.String,System.Byte)"> | ||||
|             <summary> | ||||
|             解析地址 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ParseFrom(System.String,ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress)"> | ||||
|             <summary> | ||||
|             解析地址 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress.ToString"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.AddCrc(System.Byte[])"> | ||||
|             <summary> | ||||
|             添加Crc16 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.AddModbusTcpHead(System.Byte[],System.UInt16)"> | ||||
|             <summary> | ||||
|             添加ModbusTcp报文头 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetAddressDescription"> | ||||
|             <summary> | ||||
|             modbus地址格式说明 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetDescriptionByErrorCode(System.Byte)"> | ||||
|             <summary> | ||||
|             通过错误码来获取到对应的文本消息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetModbusData(System.Byte[],System.Byte[])"> | ||||
|             <summary> | ||||
|             获取modbus数据区内容,返回数据需去除Crc和报文头,例如:01 03 02 00 01,发送数据需报文头 | ||||
|             </summary> | ||||
|             <param name="send">发送数据</param> | ||||
|             <param name="response">返回数据</param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetModbusRtuData(System.Byte[],System.Byte[],System.Boolean)"> | ||||
|             <summary> | ||||
|             去除Crc,返回modbus数据区 | ||||
|             </summary> | ||||
|             <param name="send"></param> | ||||
|             <param name="response"></param> | ||||
|             <param name="crcCheck"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetReadModbusCommand(System.String,System.Int32,System.Byte)"> | ||||
|             <summary> | ||||
|             获取读取报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteBoolModbusCommand(System.String,System.Boolean[],System.Byte)"> | ||||
|             <summary> | ||||
|             获取写入布尔量报文,根据地址识别功能码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteModbusCommand(System.String,System.Byte[],System.Byte)"> | ||||
|             <summary> | ||||
|             获取写入字报文,根据地址识别功能码 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetReadModbusCommand(ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress,System.Int32)"> | ||||
|             <summary> | ||||
|             获取读取报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteBoolModbusCommand(System.String,System.Boolean,System.Byte)"> | ||||
|             <summary> | ||||
|             获取05写入布尔量报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteBoolModbusCommand(ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress,System.Boolean)"> | ||||
|             <summary> | ||||
|             获取05写入布尔量报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteBoolModbusCommand(ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress,System.Boolean[],System.Int32)"> | ||||
|             <summary> | ||||
|             获取15写入布尔量报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteModbusCommand(ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress,System.Byte[])"> | ||||
|             <summary> | ||||
|             获取16写入字报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusHelper.GetWriteOneModbusCommand(ThingsGateway.Foundation.Adapter.Modbus.ModbusAddress,System.Byte[])"> | ||||
|             <summary> | ||||
|             获取6写入字报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.#ctor(ThingsGateway.Foundation.Sockets.TcpClient)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Crc16CheckEnable"> | ||||
|             <summary> | ||||
|             Crc校验 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Station"> | ||||
|             <summary> | ||||
|             站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Read(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.SetDataAdapter(System.Object)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Write(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.#ctor(ThingsGateway.Foundation.Sockets.UdpSession)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Crc16CheckEnable"> | ||||
|             <summary> | ||||
|             Crc校验 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Station"> | ||||
|             <summary> | ||||
|             站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Read(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.SetDataAdapter(System.Object)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Write(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter.Crc16CheckEnable"> | ||||
|             <summary> | ||||
|             检测CRC | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuOverUdpDataHandleAdapter.UnpackResponse(System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu"> | ||||
|             <summary> | ||||
|             ModbusRtu | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.#ctor(ThingsGateway.Foundation.Serial.SerialSession)"> | ||||
|             <summary> | ||||
|             ModbusRtu | ||||
|             </summary> | ||||
|             <param name="serialSession"></param> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Crc16CheckEnable"> | ||||
|             <summary> | ||||
|             Crc校验 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Station"> | ||||
|             <summary> | ||||
|             站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Read(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.SetDataAdapter(System.Object)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Write(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.Write(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtu.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuDataHandleAdapter"> | ||||
|             <summary> | ||||
|             Rtu适配器 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuDataHandleAdapter.Crc16CheckEnable"> | ||||
|             <summary> | ||||
|             检测CRC | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuDataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|             <param name="command"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuDataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuDataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuMessage,System.Byte[],System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuMessage"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuMessage.HeadBytesLength"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuMessage.CheckHeadBytes(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusRtuMessage.SendBytesThen"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ModbusServer01ByteBlocks"> | ||||
|             <summary> | ||||
|             继电器 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ModbusServer02ByteBlocks"> | ||||
|             <summary> | ||||
|             开关输入 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ModbusServer03ByteBlocks"> | ||||
|             <summary> | ||||
|             输入寄存器 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ModbusServer04ByteBlocks"> | ||||
|             <summary> | ||||
|             保持寄存器 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteData"> | ||||
|             <summary> | ||||
|             接收外部写入时,传出变量地址/写入字节组/转换规则/客户端 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.#ctor(ThingsGateway.Foundation.Sockets.TcpService)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.MulStation"> | ||||
|             <summary> | ||||
|             多站点 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Station"> | ||||
|             <summary> | ||||
|             默认站点 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Dispose"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Read(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.SetDataAdapter(System.Object)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Write(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Write(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServer.Received(ThingsGateway.Foundation.Sockets.SocketClient,ThingsGateway.Foundation.Core.IRequestInfo)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|             <param name="command"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter.GetModbusData(System.Byte[])"> | ||||
|             <summary> | ||||
|             获取modbus写入数据区内容 | ||||
|             </summary> | ||||
|             <param name="response">返回数据</param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerDataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage,System.Byte[],System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.CurModbusAddress"> | ||||
|             <summary> | ||||
|             当前关联的地址 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.Length"> | ||||
|             <summary> | ||||
|             当前读写的数据长度 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.HeadBytesLength"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusServerMessage.CheckHeadBytes(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.#ctor(ThingsGateway.Foundation.Sockets.TcpClient)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.IsCheckMessageId"> | ||||
|             <summary> | ||||
|             检测事务标识符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Station"> | ||||
|             <summary> | ||||
|             站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Read(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.SetDataAdapter(System.Object)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Write(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter"> | ||||
|             <summary> | ||||
|             ModbusTcpDataHandleAdapter | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter.IsCheckMessageId"> | ||||
|             <summary> | ||||
|             检测事务标识符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpDataHandleAdapter.UnpackResponse(ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpMessage,System.Byte[],System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpMessage"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpMessage.HeadBytesLength"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpMessage.IsCheckMessageId"> | ||||
|             <summary> | ||||
|             检测事务标识符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusTcpMessage.CheckHeadBytes(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.#ctor(ThingsGateway.Foundation.Sockets.UdpSession)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.IsCheckMessageId"> | ||||
|             <summary> | ||||
|             检测事务标识符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Station"> | ||||
|             <summary> | ||||
|             站号 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.LoadSourceRead``2(System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.GetAddressDescription"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Read(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.ReadAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.SetDataAdapter(System.Object)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Write(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.Write(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.WriteAsync(System.String,System.Byte[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdp.WriteAsync(System.String,System.Boolean[],System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter.IsCheckMessageId"> | ||||
|             <summary> | ||||
|             检测事务标识符 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter.PackCommand(System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter.GetInstance"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.ModbusUdpDataHandleAdapter.UnpackResponse(System.Byte[],System.Byte[])"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Foundation.Adapter.Modbus.PackHelper"> | ||||
|             <summary> | ||||
|             PackHelper | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Foundation.Adapter.Modbus.PackHelper.ModbusLoadSourceRead``2(ThingsGateway.Foundation.Core.IReadWrite,System.Collections.Generic.List{``1},System.Int32)"> | ||||
|             <summary> | ||||
|             打包变量,添加到<see href="deviceVariableSourceReads"></see> | ||||
|             </summary> | ||||
|             <param name="device"></param> | ||||
|             <param name="deviceVariables"></param> | ||||
|             <param name="MaxPack">最大打包长度</param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|     </members> | ||||
| </doc> | ||||
| @@ -1,57 +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.Adapter.OPCDA.Da; | ||||
|  | ||||
| /// <summary> | ||||
| /// 值变化 | ||||
| /// </summary> | ||||
| /// <param name="opcItems"></param> | ||||
| public delegate void OnDataChangedHandler(List<ItemReadResult> opcItems); | ||||
| /// <summary> | ||||
| /// 读取 | ||||
| /// </summary> | ||||
| /// <param name="opcItems"></param> | ||||
| public delegate void OnReadCompletedHandler(List<ItemReadResult> opcItems); | ||||
| /// <summary> | ||||
| /// 写入 | ||||
| /// </summary> | ||||
| /// <param name="opcItems"></param> | ||||
| internal delegate void OnWriteCompletedHandler(List<ItemWriteResult> opcItems); | ||||
| /// <summary> | ||||
| /// 返回结果 | ||||
| /// </summary> | ||||
| public class ItemReadResult | ||||
| { | ||||
|     /// <summary> | ||||
|     /// ID | ||||
|     /// </summary> | ||||
|     public string Name { get; set; } = ""; | ||||
|     /// <summary> | ||||
|     /// Quality | ||||
|     /// </summary> | ||||
|     public short Quality { get; set; } | ||||
|     /// <summary> | ||||
|     /// TimeStamp | ||||
|     /// </summary> | ||||
|     public DateTime TimeStamp { get; set; } | ||||
|     /// <summary> | ||||
|     /// Value | ||||
|     /// </summary> | ||||
|     public object Value { get; set; } = 0; | ||||
| } | ||||
|  | ||||
| internal class ItemWriteResult | ||||
| { | ||||
|     internal int Exception { get; set; } = 0; | ||||
|     internal string Name { get; set; } = ""; | ||||
| } | ||||
| @@ -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 | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.OPCDA; | ||||
|  | ||||
| internal static class CollectionExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 移除符合条件的元素 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="T"></typeparam> | ||||
|     /// <param name="this"></param> | ||||
|     /// <param name="where"></param> | ||||
|     internal static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where) | ||||
|     { | ||||
|         foreach (var obj in @this.Where(where).ToList()) | ||||
|         { | ||||
|             @this.Remove(obj); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 将项目列表分解为特定大小的块 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="T"></typeparam> | ||||
|     /// <param name="source"></param> | ||||
|     /// <param name="chunksize"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static List<List<T>> ChunkTrivialBetter<T>(this IEnumerable<T> source, int chunksize) | ||||
|     { | ||||
|         var pos = 0; | ||||
|         List<List<T>> n = new(); | ||||
|         while (source.Skip(pos).Any()) | ||||
|         { | ||||
|             n.Add(source.Skip(pos).Take(chunksize).ToList()); | ||||
|             pos += chunksize; | ||||
|         } | ||||
|         return n; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,123 +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.Collections.Concurrent; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.OPCDA; | ||||
|  | ||||
| /// <summary> | ||||
| /// DictionaryExtension | ||||
| /// </summary> | ||||
| internal static class DictionaryExtension | ||||
| { | ||||
|     #region 字典扩展 | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 移除满足条件的项目。 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TKey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="pairs"></param> | ||||
|     /// <param name="func"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static int RemoveWhen<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> pairs, Func<KeyValuePair<TKey, TValue>, bool> func) | ||||
|     { | ||||
|         var list = new List<TKey>(); | ||||
|         foreach (var item in pairs) | ||||
|         { | ||||
|             if (func?.Invoke(item) == true) | ||||
|             { | ||||
|                 list.Add(item.Key); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         var count = 0; | ||||
|         foreach (var item in list) | ||||
|         { | ||||
|             if (pairs.TryRemove(item, out _)) | ||||
|             { | ||||
|                 count++; | ||||
|             } | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
|  | ||||
| #if NET45_OR_GREATER || NETSTANDARD2_0_OR_GREATER | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 尝试添加 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="Tkey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="dictionary"></param> | ||||
|     /// <param name="tkey"></param> | ||||
|     /// <param name="value"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static bool TryAdd<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value) | ||||
|     { | ||||
|         if (dictionary.ContainsKey(tkey)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         dictionary.Add(tkey, value); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| #endif | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 尝试添加 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="Tkey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="dictionary"></param> | ||||
|     /// <param name="tkey"></param> | ||||
|     /// <param name="value"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static void AddOrUpdate<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value) | ||||
|     { | ||||
|         if (dictionary.ContainsKey(tkey)) | ||||
|         { | ||||
|             dictionary[tkey] = value; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             dictionary.Add(tkey, value); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取值。如果键不存在,则返回默认值。 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="Tkey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="dictionary"></param> | ||||
|     /// <param name="tkey"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static TValue GetValue<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey) | ||||
|     { | ||||
|         return dictionary.TryGetValue(tkey, out var value) ? value : default; | ||||
|     } | ||||
|     #endregion 字典扩展 | ||||
| } | ||||
| @@ -1,17 +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 System; | ||||
| global using System.Collections.Generic; | ||||
| global using System.Linq; | ||||
| global using System.Threading; | ||||
|  | ||||
| @@ -1,457 +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.Runtime.InteropServices; | ||||
| using System.Text; | ||||
| using System.Timers; | ||||
|  | ||||
| using ThingsGateway.Foundation.Adapter.OPCDA.Da; | ||||
| using ThingsGateway.Foundation.Adapter.OPCDA.Rcw; | ||||
|  | ||||
| using Timer = System.Timers.Timer; | ||||
|  | ||||
| //部分非托管交互代码来自https://gitee.com/Zer0Day/opc-client与OPC基金会opcnet库,更改部分逻辑 | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.OPCDA; | ||||
| /// <summary> | ||||
| /// 订阅变化项 | ||||
| /// </summary> | ||||
| /// <param name="values"></param> | ||||
| public delegate void DataChangedEventHandler(List<ItemReadResult> values); | ||||
| /// <summary> | ||||
| /// OPCDAClient | ||||
| /// </summary> | ||||
| public class OPCDAClient : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// LogAction | ||||
|     /// </summary> | ||||
|     private readonly Action<byte, object, string, Exception> _logAction; | ||||
|  | ||||
|     private readonly object checkLock = new(); | ||||
|  | ||||
|     private Timer checkTimer; | ||||
|  | ||||
|     private int IsExit = 1; | ||||
|     /// <summary> | ||||
|     /// 当前保存的需订阅列表 | ||||
|     /// </summary> | ||||
|     private Dictionary<string, List<OpcItem>> ItemDicts = new(); | ||||
|  | ||||
|     private OpcServer m_server; | ||||
|     private bool publicConnect; | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public OPCDAClient(Action<byte, object, string, Exception> logAction) | ||||
|     { | ||||
| #if (NET6_0_OR_GREATER) | ||||
|         if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||||
|         { | ||||
|             throw new NotSupportedException("不支持非windows系统"); | ||||
|         } | ||||
| #endif | ||||
|         _logAction = logAction; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 数据变化事件 | ||||
|     /// </summary> | ||||
|     public event DataChangedEventHandler DataChangedHandler; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 是否连接成功 | ||||
|     /// </summary> | ||||
|     public bool IsConnected => m_server?.IsConnected == true; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 当前配置 | ||||
|     /// </summary> | ||||
|     public OPCNode OPCNode { get; private set; } | ||||
|     private List<OpcGroup> Groups => m_server.OpcGroups; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 添加节点,需要在连接成功后执行 | ||||
|     /// </summary> | ||||
|     /// <param name="items">组名称/变量节点,注意每次添加的组名称不能相同</param> | ||||
|     public void AddItems(Dictionary<string, List<OpcItem>> items) | ||||
|     { | ||||
|         if (IsExit == 1) throw new("对象已释放"); | ||||
|         foreach (var item in items) | ||||
|         { | ||||
|             if (IsExit == 1) throw new("对象已释放"); | ||||
|             try | ||||
|             { | ||||
|                 var subscription = m_server.AddGroup(item.Key, true, OPCNode.UpdateRate, OPCNode.DeadBand); | ||||
|                 subscription.ActiveSubscribe = OPCNode.ActiveSubscribe; | ||||
|                 subscription.OnDataChanged += Subscription_OnDataChanged; | ||||
|                 subscription.OnReadCompleted += Subscription_OnDataChanged; | ||||
|  | ||||
|                 var result = subscription.AddOpcItem(item.Value.ToArray()); | ||||
|                 StringBuilder stringBuilder = new StringBuilder(); | ||||
|                 if (result.Count > 0) | ||||
|                 { | ||||
|                     foreach (var item1 in result) | ||||
|                     { | ||||
|                         stringBuilder.Append($"{item1.Item1.ItemID}:{item1.Item2}"); | ||||
|                     } | ||||
|                     _logAction?.Invoke(3, this, $"添加变量失败:{stringBuilder}", null); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ItemDicts.AddOrUpdate(item.Key, item.Value.Where(a => !result.Select(b => b.Item1).Contains(a)).ToList()); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _logAction?.Invoke(3, this, $"添加组失败:{ex.Message}", ex); | ||||
|             } | ||||
|         } | ||||
|         for (int i = 0; i < Groups?.Count; i++) | ||||
|         { | ||||
|             var group = Groups[i]; | ||||
|             if (group != null) | ||||
|             { | ||||
|                 if (group.OpcItems.Count == 0) | ||||
|                 { | ||||
|                     ItemDicts.Remove(group.Name); | ||||
|                     m_server.RemoveGroup(group); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 设置节点并保存,每次重连会自动添加节点 | ||||
|     /// </summary> | ||||
|     /// <param name="items"></param> | ||||
|     /// <returns></returns> | ||||
|     public Dictionary<string, List<OpcItem>> AddItemsWithSave(List<string> items) | ||||
|     { | ||||
|         int i = 0; | ||||
|         ItemDicts = items.ToList().ConvertAll(o => new OpcItem(o)).ChunkTrivialBetter(OPCNode.GroupSize).ToDictionary(a => "default" + (i++)); | ||||
|         return ItemDicts; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 连接服务器 | ||||
|     /// </summary> | ||||
|     public void Connect() | ||||
|     { | ||||
|         publicConnect = true; | ||||
|         Interlocked.CompareExchange(ref IsExit, 0, 1); | ||||
|         PrivateConnect(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 断开连接 | ||||
|     /// </summary> | ||||
|     public void Disconnect() | ||||
|     { | ||||
|         Interlocked.CompareExchange(ref IsExit, 1, 0); | ||||
|         PrivateDisconnect(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public void Dispose() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             PrivateDisconnect(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _logAction?.Invoke(3, this, $"连接释放失败:{ex.Message}", ex); | ||||
|         } | ||||
|         Interlocked.CompareExchange(ref IsExit, 1, 0); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 浏览节点 | ||||
|     /// </summary> | ||||
|     /// <param name="itemId"></param> | ||||
|     /// <returns></returns> | ||||
|     public List<BrowseElement> GetBrowseElements(string itemId = null) | ||||
|     { | ||||
|         return this.m_server?.Browse(itemId); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取服务状态 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public ServerStatus GetServerStatus() | ||||
|     { | ||||
|         return this.m_server?.GetServerStatus(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 初始化设置 | ||||
|     /// </summary> | ||||
|     /// <param name="node"></param> | ||||
|     public void Init(OPCNode node) | ||||
|     { | ||||
|         if (node != null) | ||||
|             OPCNode = node; | ||||
|         checkTimer?.Stop(); | ||||
|         checkTimer?.Dispose(); | ||||
|         checkTimer = new Timer(OPCNode.CheckRate * 60 * 1000); | ||||
|         checkTimer.Elapsed += CheckTimer_Elapsed; | ||||
|         checkTimer.Start(); | ||||
|         try | ||||
|         { | ||||
|             m_server?.Dispose(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _logAction?.Invoke(3, this, $"连接释放失败:{ex.Message}", ex); | ||||
|         } | ||||
|         m_server = new OpcServer(OPCNode.OPCName, OPCNode.OPCIP); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 按OPC组读取组内变量,结果会在订阅事件中返回 | ||||
|     /// </summary> | ||||
|     /// <param name="groupName">组名称,值为null时读取全部组</param> | ||||
|     /// <returns></returns> | ||||
|     public void ReadItemsWithGroup(string groupName = null) | ||||
|     { | ||||
|         PrivateConnect(); | ||||
|         { | ||||
|             var groups = groupName != null ? Groups.Where(a => a.Name == groupName) : Groups; | ||||
|             foreach (var group in groups) | ||||
|             { | ||||
|                 if (group.OpcItems.Count > 0) | ||||
|                 { | ||||
|                     group.ReadAsync(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 移除节点 | ||||
|     /// </summary> | ||||
|     /// <param name="items"></param> | ||||
|     public void RemoveItems(List<string> items) | ||||
|     { | ||||
|         foreach (var item in items) | ||||
|         { | ||||
|             if (IsExit == 1) return; | ||||
|             var opcGroups = Groups.Where(it => it.OpcItems.Any(a => a.ItemID == item)); | ||||
|             foreach (var opcGroup in opcGroups) | ||||
|             { | ||||
|                 var tag = opcGroup.OpcItems.Where(a => item == a.ItemID); | ||||
|                 var result = opcGroup.RemoveItem(tag.ToArray()); | ||||
|  | ||||
|                 if (opcGroup.OpcItems.Count == 0) | ||||
|                 { | ||||
|                     opcGroup.OnDataChanged -= Subscription_OnDataChanged; | ||||
|                     ItemDicts.Remove(opcGroup.Name); | ||||
|                     m_server.RemoveGroup(opcGroup); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ItemDicts[opcGroup.Name].RemoveWhere(a => tag.Contains(a) && !result.Select(b => b.Item1).Contains(a)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|  | ||||
|         } | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return OPCNode?.ToString(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 批量写入值 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public Dictionary<string, Tuple<bool, string>> WriteItem(Dictionary<string, object> writeInfos) | ||||
|     { | ||||
|         PrivateConnect(); | ||||
|         Dictionary<string, Tuple<bool, string>> results = new(); | ||||
|  | ||||
|         var valueGroup = writeInfos.GroupBy(itemId => | ||||
|           { | ||||
|               var group = Groups.FirstOrDefault(it => it.OpcItems.Any(a => a.ItemID == itemId.Key)); | ||||
|               return group; | ||||
|           }).ToList(); | ||||
|  | ||||
|         foreach (var item1 in valueGroup) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (item1.Key == null) | ||||
|                 { | ||||
|                     foreach (var item2 in item1) | ||||
|                     { | ||||
|                         results.AddOrUpdate(item2.Key, Tuple.Create(true, $"不存在该变量{item2.Key}")); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     List<int> serverHandles = new(); | ||||
|                     Dictionary<int, OpcItem> handleItems = new(); | ||||
|                     List<object> values = new(); | ||||
|                     foreach (var item2 in item1) | ||||
|                     { | ||||
|                         var opcItem = item1.Key.OpcItems.Where(it => it.ItemID == item2.Key).FirstOrDefault(); | ||||
|                         serverHandles.Add(opcItem.ServerHandle); | ||||
|                         handleItems.AddOrUpdate(opcItem.ServerHandle, opcItem); | ||||
|                         var rawWriteValue = item2.Value; | ||||
|                         values.Add(rawWriteValue); | ||||
|                     } | ||||
|  | ||||
|                     var result = item1.Key.Write(values.ToArray(), serverHandles.ToArray()); | ||||
|                     var data = item1.ToList(); | ||||
|                     foreach (var item2 in result) | ||||
|                     { | ||||
|                         results.AddOrUpdate(handleItems[item2.Item1].ItemID, Tuple.Create(true, $"错误代码{item2.Item2}")); | ||||
|                     } | ||||
|                 } | ||||
|                 foreach (var item2 in item1) | ||||
|                 { | ||||
|                     results.AddOrUpdate(item2.Key, Tuple.Create(false, $"成功")); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 var keys = writeInfos.Keys.ToList(); | ||||
|                 foreach (var item in keys) | ||||
|                 { | ||||
|                     results.AddOrUpdate(item, Tuple.Create(true, ex.Message)); | ||||
|                 } | ||||
|                 return results; | ||||
|             } | ||||
|         } | ||||
|         return results; | ||||
|     } | ||||
|     private void CheckTimer_Elapsed(object sender, ElapsedEventArgs e) | ||||
|     { | ||||
|         lock (checkLock) | ||||
|         { | ||||
|  | ||||
|             if (IsExit == 0) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var status = m_server.GetServerStatus(); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     if (IsExit == 0 && publicConnect) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             PrivateConnect(); | ||||
|                             _logAction?.Invoke(1, this, $"重新链接成功", null); | ||||
|                         } | ||||
|                         catch (Exception ex) | ||||
|                         { | ||||
|                             _logAction?.Invoke(3, this, $"重新链接失败:{ex.Message}", ex); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var timeer = sender as Timer; | ||||
|                 timeer.Enabled = false; | ||||
|                 timeer.Stop(); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void PrivateAddItems() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             AddItems(ItemDicts); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _logAction?.Invoke(3, this, $"添加点位失败:{ex.Message}", ex); | ||||
|         } | ||||
|     } | ||||
|     private void PrivateConnect() | ||||
|     { | ||||
|         lock (this) | ||||
|         { | ||||
|  | ||||
|             if (m_server?.IsConnected == true) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var status = m_server.GetServerStatus(); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         var status1 = m_server.GetServerStatus(); | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|  | ||||
|                         Init(OPCNode); | ||||
|                         m_server?.Connect(); | ||||
|                         _logAction?.Invoke(1, this, $"{m_server.Host} - {m_server.Name} - 连接成功", null); | ||||
|                         PrivateAddItems(); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Init(OPCNode); | ||||
|                 m_server?.Connect(); | ||||
|                 _logAction?.Invoke(1, this, $"{m_server.Host} - {m_server.Name} - 连接成功", null); | ||||
|                 PrivateAddItems(); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void PrivateDisconnect() | ||||
|     { | ||||
|         lock (this) | ||||
|         { | ||||
|             if (IsConnected) | ||||
|                 _logAction?.Invoke(1, this, $"{m_server.Host} - {m_server.Name} - 断开连接", null); | ||||
|             if (checkTimer != null) | ||||
|             { | ||||
|                 checkTimer.Enabled = false; | ||||
|                 checkTimer.Stop(); | ||||
|             } | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 m_server?.Dispose(); | ||||
|                 m_server = null; | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _logAction?.Invoke(3, this, $"连接释放失败:{ex.Message}", ex); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     private void Subscription_OnDataChanged(List<ItemReadResult> values) | ||||
|     { | ||||
|         DataChangedHandler?.Invoke(values); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,64 +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.Adapter.OPCDA; | ||||
| /// <summary> | ||||
| /// OPCDA连接配置项 | ||||
| /// </summary> | ||||
| public class OPCNode | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 是否订阅 | ||||
|     /// </summary> | ||||
|     [Description("订阅")] | ||||
|     public bool ActiveSubscribe { get; set; } = true; | ||||
|     /// <summary> | ||||
|     /// 内部检测重连间隔/min | ||||
|     /// </summary> | ||||
|     [Description("重连间隔/min")] | ||||
|     public int CheckRate { get; set; } = 30; | ||||
|     /// <summary> | ||||
|     /// 死区 | ||||
|     /// </summary> | ||||
|     [Description("死区")] | ||||
|     public float DeadBand { get; set; } = 0; | ||||
|     /// <summary> | ||||
|     /// 分组大小 | ||||
|     /// </summary> | ||||
|     [Description("分组大小")] | ||||
|     public int GroupSize { get; set; } = 500; | ||||
|     /// <summary> | ||||
|     /// OPCIP | ||||
|     /// </summary> | ||||
|     [Description("OPCIP")] | ||||
|     public string OPCIP { get; set; } = "localhost"; | ||||
|     /// <summary> | ||||
|     /// OPCNAME | ||||
|     /// </summary> | ||||
|     [Description("OPCNAME")] | ||||
|     public string OPCName { get; set; } = "Kepware.KEPServerEX.V6"; | ||||
|     /// <summary> | ||||
|     /// 订阅间隔 | ||||
|     /// </summary> | ||||
|     [Description("订阅间隔")] | ||||
|     public int UpdateRate { get; set; } = 1000; | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return $"{(string.IsNullOrEmpty(OPCIP) ? "localhost" : OPCIP)}:{OPCName}"; | ||||
|     } | ||||
| } | ||||
| @@ -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.Core.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,17 +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 System; | ||||
| global using System.Collections.Generic; | ||||
| global using System.Linq; | ||||
| global using System.Threading; | ||||
| global using System.Threading.Tasks; | ||||
| @@ -1,78 +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.Adapter.OPCUA; | ||||
| /// <summary> | ||||
| /// OPCUAClient配置项 | ||||
| /// </summary> | ||||
| public class OPCNode | ||||
| { | ||||
|     /// <summary> | ||||
|     /// OPCUrl | ||||
|     /// </summary> | ||||
|     [Description("OPCUrl")] | ||||
|     public string OPCUrl { get; set; } = "opc.tcp://127.0.0.1:49320"; | ||||
|     /// <summary> | ||||
|     /// 登录账号 | ||||
|     /// </summary> | ||||
|     [Description("登录账号")] | ||||
|     public string UserName { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 登录密码 | ||||
|     /// </summary> | ||||
|     [Description("登录密码")] | ||||
|     public string Password { get; set; } | ||||
|     /// <summary> | ||||
|     /// 检查域 | ||||
|     /// </summary> | ||||
|     [Description("检查域")] | ||||
|     public bool CheckDomain { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 更新间隔 | ||||
|     /// </summary> | ||||
|     [Description("更新间隔")] | ||||
|     public int UpdateRate { get; set; } = 1000; | ||||
|     /// <summary> | ||||
|     /// 是否订阅 | ||||
|     /// </summary> | ||||
|     [Description("是否订阅")] | ||||
|     public bool ActiveSubscribe { get; set; } = true; | ||||
|     /// <summary> | ||||
|     /// 分组大小 | ||||
|     /// </summary> | ||||
|     [Description("分组大小")] | ||||
|     public int GroupSize { get; set; } = 500; | ||||
|     /// <summary> | ||||
|     /// 死区 | ||||
|     /// </summary> | ||||
|     [Description("死区")] | ||||
|     public double DeadBand { get; set; } = 0; | ||||
|     /// <summary> | ||||
|     /// KeepAliveInterval/ms | ||||
|     /// </summary> | ||||
|     [Description("KeepAliveInterval/ms")] | ||||
|     public int KeepAliveInterval { get; set; } = 3000; | ||||
|     /// <summary> | ||||
|     /// 安全策略 | ||||
|     /// </summary> | ||||
|     [Description("安全策略")] | ||||
|     public bool IsUseSecurity { get; set; } = false; | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return OPCUrl; | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,15 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks> | ||||
|  | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> | ||||
| 		<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.372.56" /> | ||||
| 		<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.4.372.56" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
| </Project> | ||||
| @@ -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.Core.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,43 +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.Adapter.OPCUA; | ||||
|  | ||||
| internal static class CollectionExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 移除符合条件的元素 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="T"></typeparam> | ||||
|     /// <param name="this"></param> | ||||
|     /// <param name="where"></param> | ||||
|     internal static void RemoveWhere<T>(this ICollection<T> @this, Func<T, bool> @where) | ||||
|     { | ||||
|         foreach (var obj in @this.Where(where).ToList()) | ||||
|         { | ||||
|             @this.Remove(obj); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 异步Select | ||||
|     /// </summary> | ||||
|     /// <typeparam name="T"></typeparam> | ||||
|     /// <typeparam name="TResult"></typeparam> | ||||
|     /// <param name="source"></param> | ||||
|     /// <param name="selector"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static Task<TResult[]> SelectAsync<T, TResult>(this IEnumerable<T> source, Func<T, Task<TResult>> selector) | ||||
|     { | ||||
|         return Task.WhenAll(source.Select(selector)); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,123 +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.Collections.Concurrent; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.OPCUA; | ||||
|  | ||||
| /// <summary> | ||||
| /// DictionaryExtension | ||||
| /// </summary> | ||||
| internal static class DictionaryExtension | ||||
| { | ||||
|     #region 字典扩展 | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 移除满足条件的项目。 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TKey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="pairs"></param> | ||||
|     /// <param name="func"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static int RemoveWhen<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> pairs, Func<KeyValuePair<TKey, TValue>, bool> func) | ||||
|     { | ||||
|         var list = new List<TKey>(); | ||||
|         foreach (var item in pairs) | ||||
|         { | ||||
|             if (func?.Invoke(item) == true) | ||||
|             { | ||||
|                 list.Add(item.Key); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         var count = 0; | ||||
|         foreach (var item in list) | ||||
|         { | ||||
|             if (pairs.TryRemove(item, out _)) | ||||
|             { | ||||
|                 count++; | ||||
|             } | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
|  | ||||
| #if NET45_OR_GREATER || NETSTANDARD2_0_OR_GREATER | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 尝试添加 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="Tkey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="dictionary"></param> | ||||
|     /// <param name="tkey"></param> | ||||
|     /// <param name="value"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static bool TryAdd<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value) | ||||
|     { | ||||
|         if (dictionary.ContainsKey(tkey)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         dictionary.Add(tkey, value); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| #endif | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 尝试添加 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="Tkey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="dictionary"></param> | ||||
|     /// <param name="tkey"></param> | ||||
|     /// <param name="value"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static void AddOrUpdate<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey, TValue value) | ||||
|     { | ||||
|         if (dictionary.ContainsKey(tkey)) | ||||
|         { | ||||
|             dictionary[tkey] = value; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             dictionary.Add(tkey, value); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取值。如果键不存在,则返回默认值。 | ||||
|     /// </summary> | ||||
|     /// <typeparam name="Tkey"></typeparam> | ||||
|     /// <typeparam name="TValue"></typeparam> | ||||
|     /// <param name="dictionary"></param> | ||||
|     /// <param name="tkey"></param> | ||||
|     /// <returns></returns> | ||||
|     internal static TValue GetValue<Tkey, TValue>(this Dictionary<Tkey, TValue> dictionary, Tkey tkey) | ||||
|     { | ||||
|         return dictionary.TryGetValue(tkey, out var value) ? value : default; | ||||
|     } | ||||
|     #endregion 字典扩展 | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,20 +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 System; | ||||
| global using System.Collections.Generic; | ||||
| global using System.Linq; | ||||
| global using System.Threading; | ||||
| global using System.Threading.Tasks; | ||||
|  | ||||
| global using ThingsGateway.Foundation.Core; | ||||
| global using ThingsGateway.Foundation.Sockets; | ||||
| @@ -1,293 +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.Extension; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Siemens; | ||||
| /// <summary> | ||||
| /// 区域 | ||||
| /// </summary> | ||||
| public enum S7Area : byte | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     PE = 0x81, | ||||
|     /// <inheritdoc/> | ||||
|     PA = 0x82, | ||||
|     /// <inheritdoc/> | ||||
|     MK = 0x83, | ||||
|     /// <inheritdoc/> | ||||
|     DB = 0x84, | ||||
|     /// <inheritdoc/> | ||||
|     CT = 0x1C, | ||||
|     /// <inheritdoc/> | ||||
|     TM = 0x1D, | ||||
|     /// <inheritdoc/> | ||||
|     AI = 0X06, | ||||
|     /// <inheritdoc/> | ||||
|     AQ = 0x07, | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| /// 西门子PLC地址数据信息 | ||||
| /// </summary> | ||||
| public class SiemensAddress : DeviceAddressBase | ||||
| { | ||||
|     /// <summary> | ||||
|     /// bit位偏移 | ||||
|     /// </summary> | ||||
|     public byte BitCode { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 数据块代码 | ||||
|     /// </summary> | ||||
|     public byte DataCode { get; set; } | ||||
|     /// <summary> | ||||
|     /// DB块数据信息 | ||||
|     /// </summary> | ||||
|     public ushort DbBlock { get; set; } | ||||
|     /// <summary> | ||||
|     /// IsWString,默认是true,如果不是WString,需要填写W=false; | ||||
|     /// </summary> | ||||
|     public bool IsWString { get; set; } = true; | ||||
|     /// <summary> | ||||
|     /// 获取起始地址 | ||||
|     /// </summary> | ||||
|     /// <param name="address"></param> | ||||
|     /// <param name="isCounterOrTimer"></param> | ||||
|     /// <returns></returns> | ||||
|     public static int GetAddressStart(string address, bool isCounterOrTimer = false) | ||||
|     { | ||||
|         if (address.IndexOf('.') < 0) | ||||
|         { | ||||
|             return isCounterOrTimer ? Convert.ToInt32(address) : Convert.ToInt32(address) * 8; | ||||
|         } | ||||
|  | ||||
|         string[] strArray = address.Split('.'); | ||||
|         return Convert.ToInt32(strArray[0]) * 8; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 获取bit | ||||
|     /// </summary> | ||||
|     /// <param name="address"></param> | ||||
|     /// <returns></returns> | ||||
|     public static byte GetBitCode(string address) | ||||
|     { | ||||
|         if (address.IndexOf('.') < 0) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|         string[] strArray = address.Split('.'); | ||||
|         return Convert.ToByte(strArray[1]); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static SiemensAddress ParseFrom(string address, int len) | ||||
|     { | ||||
|         SiemensAddress s7AddressData = ParseFrom(address); | ||||
|         s7AddressData.Length = len; | ||||
|         return s7AddressData; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 解析地址 | ||||
|     /// </summary> | ||||
|     /// <param name="address"></param> | ||||
|     /// <returns></returns> | ||||
|     public static SiemensAddress ParseFrom(string address) | ||||
|     { | ||||
|         SiemensAddress s7AddressData = new(); | ||||
|         address = address.ToUpper(); | ||||
|         string[] strArr = address.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); | ||||
|         for (int index = 0; index < strArr.Length; ++index) | ||||
|         { | ||||
|             if (strArr[index].StartsWith("W=")) | ||||
|             { | ||||
|                 s7AddressData.IsWString = strArr[index].Substring(2).ToBoolean(true); | ||||
|             } | ||||
|             else if (!strArr[index].Contains("=")) | ||||
|             { | ||||
|  | ||||
|                 s7AddressData.DbBlock = 0; | ||||
|  | ||||
|                 if (strArr[index].StartsWith("AI")) | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.AI; | ||||
|                     if (strArr[index].StartsWith("AIX") || strArr[index].StartsWith("AIB") || strArr[index].StartsWith("AIW") || strArr[index].StartsWith("AID")) | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(3)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(3)); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2)); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (strArr[index].StartsWith("AQ")) | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.AQ; | ||||
|                     if (strArr[index].StartsWith("AQX") || strArr[index].StartsWith("AQB") || strArr[index].StartsWith("AQW") || strArr[index].StartsWith("AQD")) | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(3)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(3)); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2)); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'I') | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.PE; | ||||
|                     if (strArr[index].StartsWith("IX") || strArr[index].StartsWith("IB") || strArr[index].StartsWith("IW") || strArr[index].StartsWith("ID")) | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2)); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1)); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'Q') | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.PA; | ||||
|                     if (strArr[index].StartsWith("QX") || strArr[index].StartsWith("QB") || strArr[index].StartsWith("QW") || strArr[index].StartsWith("QD")) | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2)); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1)); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'M') | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.MK; | ||||
|                     if (strArr[index].StartsWith("MX") || strArr[index].StartsWith("MB") || strArr[index].StartsWith("MW") || strArr[index].StartsWith("MD")) | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2)); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1)); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'D' || strArr[index].Substring(0, 2) == "DB") | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.DB; | ||||
|                     string[] strArray = strArr[index].Split('.'); | ||||
|                     s7AddressData.DbBlock = strArray[index][1] != 'B' ? Convert.ToUInt16(strArray[0].Substring(1)) : Convert.ToUInt16(strArray[0].Substring(2)); | ||||
|                     string address1 = strArr[index].Substring(strArr[index].IndexOf('.') + 1); | ||||
|                     if (address1.StartsWith("DBX") || address1.StartsWith("DBB") || address1.StartsWith("DBW") || address1.StartsWith("DBD")) | ||||
|                     { | ||||
|                         address1 = address1.Substring(3); | ||||
|                     } | ||||
|  | ||||
|                     s7AddressData.Address = GetAddressStart(address1).ToString(); | ||||
|                     s7AddressData.BitCode = GetBitCode(address1); | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'T') | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.TM; | ||||
|                     s7AddressData.Address = GetAddressStart(strArr[index].Substring(1), true).ToString(); | ||||
|                     s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1)); | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'C') | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.CT; | ||||
|                     s7AddressData.Address = GetAddressStart(strArr[index].Substring(1), true).ToString(); | ||||
|                     s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1)); | ||||
|                 } | ||||
|                 else if (strArr[index][0] == 'V') | ||||
|                 { | ||||
|                     s7AddressData.DataCode = (byte)S7Area.DB; | ||||
|                     s7AddressData.DbBlock = 1; | ||||
|                     if (strArr[index].StartsWith("VB") || strArr[index].StartsWith("VW") || strArr[index].StartsWith("VD") || strArr[index].StartsWith("VX")) | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(2)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(2)); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         s7AddressData.Address = GetAddressStart(strArr[index].Substring(1)).ToString(); | ||||
|                         s7AddressData.BitCode = GetBitCode(strArr[index].Substring(1)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return s7AddressData; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Length | ||||
|     /// </summary> | ||||
|     public int Length { get; set; } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc cref="DeviceAddressBase.Address"/> | ||||
|     /// </summary> | ||||
|     public int AddressStart => Address.ToInt(); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         if (DataCode == (byte)S7Area.TM) | ||||
|         { | ||||
|             return "T" + Address.ToString() + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|         if (DataCode == (byte)S7Area.CT) | ||||
|         { | ||||
|             return "C" + Address.ToString() + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|  | ||||
|         if (DataCode == (byte)S7Area.AI) | ||||
|         { | ||||
|             return "AI" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|  | ||||
|         if (DataCode == (byte)S7Area.AQ) | ||||
|         { | ||||
|             return "AQ" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|  | ||||
|         if (DataCode == (byte)S7Area.PE) | ||||
|         { | ||||
|             return "I" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|  | ||||
|         if (DataCode == (byte)S7Area.PA) | ||||
|         { | ||||
|             return "Q" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|  | ||||
|         if (DataCode == (byte)S7Area.MK) | ||||
|         { | ||||
|             return "M" + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|         } | ||||
|  | ||||
|         return DataCode == (byte)S7Area.DB ? "DB" + DbBlock.ToString() + "." + GetStringAddress(AddressStart) + (IsWString ? ";W=true;" : ";W=false;") : Address.ToString() + (IsWString ? ";W=true;" : ";W=false;"); | ||||
|     } | ||||
|  | ||||
|     private static string GetStringAddress(int addressStart) | ||||
|     { | ||||
|         return addressStart % 8 == 0 ? (addressStart / 8).ToString() : string.Format("{0}.{1}", addressStart / 8, addressStart % 8); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,165 +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.Adapter.Siemens; | ||||
|  | ||||
| /// <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> | ||||
| public static class DateTime | ||||
| { | ||||
|     /// <summary> | ||||
|     /// The maximum <see cref="T:System.DateTime"/> value supported by the specification. | ||||
|     /// </summary> | ||||
|     public static readonly System.DateTime SpecMaximumDateTime = new(2089, 12, 31, 23, 59, 59, 999); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// The minimum <see cref="T:System.DateTime"/> value supported by the specification. | ||||
|     /// </summary> | ||||
|     public static readonly System.DateTime SpecMinimumDateTime = new(1990, 1, 1); | ||||
|     /// <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="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> | ||||
|     public static System.DateTime FromByteArray(byte[] bytes) | ||||
|     { | ||||
|         return FromByteArrayImpl(bytes); | ||||
|     } | ||||
|  | ||||
|     /// <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="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> | ||||
|     public static System.DateTime[] ToArray(byte[] bytes) | ||||
|     { | ||||
|         if (bytes.Length % 8 != 0) | ||||
|             throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length, | ||||
|                 $"Parsing an array of DateTime requires a multiple of 8 bytes of input data, input data is '{bytes.Length}' long."); | ||||
|  | ||||
|         var cnt = bytes.Length / 8; | ||||
|         var result = new System.DateTime[bytes.Length / 8]; | ||||
|  | ||||
|         for (var i = 0; i < cnt; i++) | ||||
|             result[i] = FromByteArrayImpl(new ArraySegment<byte>(bytes, i * 8, 8)); | ||||
|  | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     /// <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="ArgumentOutOfRangeException">Thrown when the value of | ||||
|     ///   <paramref name="dateTime"/> is before <see cref="P:SpecMinimumDateTime"/> | ||||
|     ///   or after <see cref="P:SpecMaximumDateTime"/>.</exception> | ||||
|     public static byte[] ToByteArray(System.DateTime dateTime) | ||||
|     { | ||||
|         byte EncodeBcd(int value) | ||||
|         { | ||||
|             return (byte)((value / 10 << 4) | value % 10); | ||||
|         } | ||||
|  | ||||
|         if (dateTime < SpecMinimumDateTime) | ||||
|             throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, | ||||
|                 $"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 date time representation."); | ||||
|  | ||||
|         if (dateTime > SpecMaximumDateTime) | ||||
|             throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, | ||||
|                 $"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 date time representation."); | ||||
|  | ||||
|         byte MapYear(int year) => (byte)(year < 2000 ? year - 1900 : year - 2000); | ||||
|  | ||||
|         int DayOfWeekToInt(DayOfWeek dayOfWeek) => (int)dayOfWeek + 1; | ||||
|  | ||||
|         return new[] | ||||
|         { | ||||
|             EncodeBcd(MapYear(dateTime.Year)), | ||||
|             EncodeBcd(dateTime.Month), | ||||
|             EncodeBcd(dateTime.Day), | ||||
|             EncodeBcd(dateTime.Hour), | ||||
|             EncodeBcd(dateTime.Minute), | ||||
|             EncodeBcd(dateTime.Second), | ||||
|             EncodeBcd(dateTime.Millisecond / 10), | ||||
|             (byte) (dateTime.Millisecond % 10 << 4 | DayOfWeekToInt(dateTime.DayOfWeek)) | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     /// <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="ArgumentOutOfRangeException">Thrown when any value of | ||||
|     ///   <paramref name="dateTimes"/> is before <see cref="P:SpecMinimumDateTime"/> | ||||
|     ///   or after <see cref="P:SpecMaximumDateTime"/>.</exception> | ||||
|     public static byte[] ToByteArray(System.DateTime[] dateTimes) | ||||
|     { | ||||
|         var bytes = new List<byte>(dateTimes.Length * 8); | ||||
|         foreach (var dateTime in dateTimes) bytes.AddRange(ToByteArray(dateTime)); | ||||
|  | ||||
|         return bytes.ToArray(); | ||||
|     } | ||||
|  | ||||
|     private static System.DateTime FromByteArrayImpl(IList<byte> bytes) | ||||
|     { | ||||
|         if (bytes.Count != 8) | ||||
|             throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Count, | ||||
|                 $"Parsing a DateTime requires exactly 8 bytes of input data, input data is {bytes.Count} bytes long."); | ||||
|  | ||||
|         int DecodeBcd(byte input) => 10 * (input >> 4) + (input & 0b00001111); | ||||
|  | ||||
|         int ByteToYear(byte bcdYear) | ||||
|         { | ||||
|             var input = DecodeBcd(bcdYear); | ||||
|             if (input < 90) return input + 2000; | ||||
|             if (input < 100) return input + 1900; | ||||
|  | ||||
|             throw new ArgumentOutOfRangeException(nameof(bcdYear), bcdYear, | ||||
|                 $"Value '{input}' is higher than the maximum '99' of S7 date and time representation."); | ||||
|         } | ||||
|  | ||||
|         int AssertRangeInclusive(int input, byte min, byte max, string field) | ||||
|         { | ||||
|             if (input < min) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(input), input, | ||||
|                     $"Value '{input}' is lower than the minimum '{min}' allowed for {field}."); | ||||
|             if (input > max) | ||||
|                 throw new ArgumentOutOfRangeException(nameof(input), input, | ||||
|                     $"Value '{input}' is higher than the maximum '{max}' allowed for {field}."); | ||||
|  | ||||
|             return input; | ||||
|         } | ||||
|  | ||||
|         var year = ByteToYear(bytes[0]); | ||||
|         var month = AssertRangeInclusive(DecodeBcd(bytes[1]), 1, 12, "month"); | ||||
|         var day = AssertRangeInclusive(DecodeBcd(bytes[2]), 1, 31, "day of month"); | ||||
|         var hour = AssertRangeInclusive(DecodeBcd(bytes[3]), 0, 23, "hour"); | ||||
|         var minute = AssertRangeInclusive(DecodeBcd(bytes[4]), 0, 59, "minute"); | ||||
|         var second = AssertRangeInclusive(DecodeBcd(bytes[5]), 0, 59, "second"); | ||||
|         var hsec = AssertRangeInclusive(DecodeBcd(bytes[6]), 0, 99, "first two millisecond digits"); | ||||
|         var msec = AssertRangeInclusive(bytes[7] >> 4, 0, 9, "third millisecond digit"); | ||||
|         _ = AssertRangeInclusive(bytes[7] & 0b00001111, 1, 7, "day of week"); | ||||
|  | ||||
|         return new System.DateTime(year, month, day, hour, minute, second, hsec * 10 + msec); | ||||
|     } | ||||
| } | ||||
| @@ -1,234 +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.Adapter.Siemens; | ||||
|  | ||||
| internal static class PackHelper | ||||
| { | ||||
|     public static List<T> LoadSourceRead<T, T2>(SiemensS7PLC siemensS7Net, List<T2> deviceVariables, int maxPack) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new() | ||||
|     { | ||||
|         var byteConverter = siemensS7Net.ThingsGatewayBitConverter; | ||||
|         var result = new List<T>(); | ||||
|  | ||||
|         //需要先剔除额外信息,比如dataformat等 | ||||
|         foreach (var item in deviceVariables) | ||||
|         { | ||||
|             var address = item.VariableAddress; | ||||
|  | ||||
|             IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, byteConverter); | ||||
|             item.ThingsGatewayBitConverter = transformParameter; | ||||
|             //item.VariableAddress = address;//需要使用过滤后的地址 | ||||
|             item.Index = siemensS7Net.GetBitOffset(item.VariableAddress); | ||||
|         } | ||||
|         //按读取间隔分组 | ||||
|         var tags = deviceVariables.GroupBy(it => it.IntervalTime); | ||||
|         foreach (var item in tags) | ||||
|         { | ||||
|             Dictionary<SiemensAddress, T2> map = item.ToDictionary(it => | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var s7Address = SiemensAddress.ParseFrom(it.VariableAddress); | ||||
|                     var lastLen = it.DataTypeEnum.GetByteLength(); | ||||
|                     if (lastLen <= 0) | ||||
|                     { | ||||
|                         switch (it.DataTypeEnum) | ||||
|                         { | ||||
|                             case DataTypeEnum.String: | ||||
|                                 if (it.ThingsGatewayBitConverter.Length == null) | ||||
|                                 { | ||||
|                                     throw new("数据类型为字符串时,必须指定字符串长度,才能进行打包"); | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     if (siemensS7Net.CurrentPlc == SiemensEnum.S200Smart) | ||||
|                                     { | ||||
|                                         if (s7Address.IsWString) | ||||
|                                         { | ||||
|                                             //字符串在S200Smart中,第一个字节不属于实际内容 | ||||
|                                             it.Index += 1; | ||||
|                                             lastLen = it.ThingsGatewayBitConverter.Length.Value + 1; | ||||
|                                         } | ||||
|                                         else | ||||
|                                         { | ||||
|                                             lastLen = it.ThingsGatewayBitConverter.Length.Value; | ||||
|                                         } | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         if (s7Address.IsWString) | ||||
|                                         { | ||||
|                                             //字符串在S7中,前两个字节不属于实际内容 | ||||
|                                             it.Index += 2; | ||||
|                                             lastLen = it.ThingsGatewayBitConverter.Length.Value + 2; | ||||
|                                         } | ||||
|                                         else | ||||
|                                         { | ||||
|                                             lastLen = it.ThingsGatewayBitConverter.Length.Value; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                                 break; | ||||
|                             default: | ||||
|                                 lastLen = 1; | ||||
|                                 break; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     if ((s7Address.DataCode == (byte)S7WordLength.Counter || s7Address.DataCode == (byte)S7WordLength.Timer) && lastLen == 1) | ||||
|                     { | ||||
|                         lastLen = 2; | ||||
|                     } | ||||
|                     if (it.ThingsGatewayBitConverter.Length != null && it.DataTypeEnum != DataTypeEnum.String) | ||||
|                     { | ||||
|                         lastLen *= it.ThingsGatewayBitConverter.Length.Value; | ||||
|                     } | ||||
|  | ||||
|                     //这里把每个变量的应读取长度都写入变量地址实体中 | ||||
|                     s7Address.Length = lastLen; | ||||
|                     return s7Address; | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     siemensS7Net.Logger.LogWarning(ex, "解析地址错误"); | ||||
|                 } | ||||
|                 return null; | ||||
|             }); | ||||
|  | ||||
|             //获取变量的地址 | ||||
|             var modbusAddressList = map.Keys.Where(a => a != null).ToList(); | ||||
|  | ||||
|             //获取S7数据代码 | ||||
|             var functionCodes = modbusAddressList.Select(t => t.DataCode).Distinct(); | ||||
|             foreach (var functionCode in functionCodes) | ||||
|             { | ||||
|                 //相同数据代码的变量集合 | ||||
|                 var modbusAddressSameFunList = modbusAddressList | ||||
|                     .Where(t => t.DataCode == functionCode); | ||||
|                 //相同数据代码的变量集合中的不同DB块 | ||||
|                 var stationNumbers = modbusAddressSameFunList | ||||
|                     .Select(t => t.DbBlock).Distinct(); | ||||
|                 foreach (var stationNumber in stationNumbers) | ||||
|                 { | ||||
|                     var addressList = modbusAddressSameFunList.Where(t => t.DbBlock == stationNumber) | ||||
|                         .ToDictionary(t => t, t => map[t]); | ||||
|                     //循环对数据代码,站号都一样的变量进行分配连读包 | ||||
|                     var tempResult = LoadSourceRead<T, T2>(addressList, functionCode, item.Key, siemensS7Net); | ||||
|                     //添加到总连读包 | ||||
|                     result.AddRange(tempResult); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     private static List<T> LoadSourceRead<T, T2>(Dictionary<SiemensAddress, T2> addressList, int functionCode, int intervalTime, SiemensS7PLC siemensS7Net) where T : IDeviceVariableSourceRead<IDeviceVariableRunTime>, new() where T2 : IDeviceVariableRunTime, new() | ||||
|     { | ||||
|  | ||||
|         List<T> sourceReads = new(); | ||||
|         //实际地址与长度排序 | ||||
|         var addresss = addressList.Keys.OrderBy(it => | ||||
|         { | ||||
|             int address = 0; | ||||
|             if (it.DataCode == (byte)S7WordLength.Counter || it.DataCode == (byte)S7WordLength.Timer) | ||||
|             { | ||||
|                 address = it.AddressStart * 2; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 address = it.AddressStart / 8; | ||||
|             } | ||||
|             return address + it.Length; | ||||
|         }).ToList(); | ||||
|         var minAddress = addresss.First().AddressStart; | ||||
|         var maxAddress = addresss.Last().AddressStart; | ||||
|         while (maxAddress >= minAddress) | ||||
|         { | ||||
|             //这里直接避免末位变量长度超限的情况,pdu长度-8 | ||||
|             int readLength = siemensS7Net.PDULength == 0 ? 200 : siemensS7Net.PDULength - 8; | ||||
|             List<SiemensAddress> tempAddress = new(); | ||||
|             if (functionCode == (byte)S7WordLength.Counter || functionCode == (byte)S7WordLength.Timer) | ||||
|             { | ||||
|                 tempAddress = addresss.Where(t => t.AddressStart >= minAddress && ((t.AddressStart) + t.Length) <= ((minAddress) + readLength)).ToList(); | ||||
|                 while ((tempAddress.Last().AddressStart * 2) + tempAddress.Last().Length - (tempAddress.First().AddressStart * 2) > readLength) | ||||
|                 { | ||||
|                     tempAddress.Remove(tempAddress.Last()); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 tempAddress = addresss.Where(t => t.AddressStart >= minAddress && ((t.AddressStart) + t.Length) <= ((minAddress) + readLength)).ToList(); | ||||
|                 while ((tempAddress.Last().AddressStart / 8) + tempAddress.Last().Length - (tempAddress.First().AddressStart / 8) > readLength) | ||||
|                 { | ||||
|                     tempAddress.Remove(tempAddress.Last()); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             //读取寄存器长度 | ||||
|             int lastAddress = 0; | ||||
|             int firstAddress = 0; | ||||
|             if (functionCode == (byte)S7WordLength.Counter || functionCode == (byte)S7WordLength.Timer) | ||||
|             { | ||||
|                 lastAddress = tempAddress.Last().AddressStart * 2; | ||||
|                 firstAddress = tempAddress.First().AddressStart * 2; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 lastAddress = tempAddress.Last().AddressStart / 8; | ||||
|                 firstAddress = tempAddress.First().AddressStart / 8; | ||||
|             } | ||||
|             var sourceLen = lastAddress + tempAddress.Last().Length - firstAddress; | ||||
|             T sourceRead = new() | ||||
|             { | ||||
|                 TimerTick = new(intervalTime), | ||||
|                 VariableAddress = tempAddress.OrderBy(it => it.AddressStart).First().ToString(), | ||||
|                 Length = sourceLen | ||||
|             }; | ||||
|             foreach (var item in tempAddress) | ||||
|             { | ||||
|                 var readNode = addressList[item]; | ||||
|                 if (functionCode == (byte)S7WordLength.Counter || functionCode == (byte)S7WordLength.Timer) | ||||
|                 { | ||||
|                     if (readNode.DataTypeEnum == DataTypeEnum.Boolean) | ||||
|                     { | ||||
|                         readNode.Index = (((item.AddressStart * 2) - (tempAddress.First().AddressStart * 2)) * 8) + readNode.Index; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         readNode.Index = (item.AddressStart * 2) - (tempAddress.First().AddressStart * 2) + readNode.Index; | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (readNode.DataTypeEnum == DataTypeEnum.Boolean) | ||||
|                     { | ||||
|                         readNode.Index = (((item.AddressStart / 8) - (tempAddress.First().AddressStart / 8)) * 8) + readNode.Index; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         readNode.Index = (item.AddressStart / 8) - (tempAddress.First().AddressStart / 8) + readNode.Index; | ||||
|                     } | ||||
|                 } | ||||
|                 sourceRead.DeviceVariableRunTimes.Add(readNode); | ||||
|                 addresss.Remove(item); | ||||
|             } | ||||
|             sourceReads.Add(sourceRead); | ||||
|             if (addresss.Count > 0) | ||||
|                 minAddress = addresss.First().AddressStart; | ||||
|             else | ||||
|                 break; | ||||
|         } | ||||
|         return sourceReads; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,383 +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.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Siemens; | ||||
|  | ||||
| internal partial class SiemensHelper | ||||
| { | ||||
|     #region 验证 | ||||
|     //internal static OperResult<byte[]> AnalysisReadBit(byte[] content) | ||||
|     //{ | ||||
|     //    int length = 1; | ||||
|     //    if (content.Length < 21 || content[20] != 1) | ||||
|     //        return new OperResult<byte[]>("数据块长度校验失败"); | ||||
|     //    byte[] numArray = new byte[length]; | ||||
|     //    if (content[21] == byte.MaxValue && content[22] == 3)//Bit:3;Byte:4;Counter或者Timer:9 | ||||
|     //    { | ||||
|     //        numArray[0] = content[25];//+4 | ||||
|     //    } | ||||
|     //    else | ||||
|     //    { | ||||
|     //        return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21])); | ||||
|     //    } | ||||
|     //    return OperResult.CreateSuccessResult<byte[]>(numArray); | ||||
|     //} | ||||
|  | ||||
|     internal static OperResult<byte[]> AnalysisReadByte(byte[] sends, byte[] content) | ||||
|     { | ||||
|         int length = 0; | ||||
|         int itemLen = (sends.Length - 19) / 12; | ||||
|  | ||||
|         for (int index = 0; index < itemLen; index++) | ||||
|         { | ||||
|             if (sends[22 + (index * 12)] >= (byte)S7WordLength.Word) | ||||
|             { | ||||
|                 length += ((sends[23 + (index * 12)] * 256) + sends[24 + (index * 12)]) * 2; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 length += (sends[23 + (index * 12)] * 256) + sends[24 + (index * 12)]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (content.Length < 21 || content[20] != itemLen) | ||||
|         { | ||||
|             return new OperResult<byte[]>("数据块长度校验失败"); | ||||
|         } | ||||
|  | ||||
|         byte[] dataArray = new byte[length]; | ||||
|         int index1 = 0; | ||||
|         int dataIndex = 0; | ||||
|         for (int index2 = 21; index2 < content.Length; index2++) | ||||
|         { | ||||
|             if (index2 + 1 < content.Length) | ||||
|             { | ||||
|                 int s7len; | ||||
|                 if (sends[22 + (index1 * 12)] >= (byte)S7WordLength.Word) | ||||
|                 { | ||||
|                     s7len = ((sends[23 + (index1 * 12)] * 256) + sends[24 + (index1 * 12)]) * 2; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     s7len = (sends[23 + (index1 * 12)] * 256) + sends[24 + (index1 * 12)]; | ||||
|                 } | ||||
|                 if (content[index2] == byte.MaxValue && content[index2 + 1] == 4)//Bit:3;Byte:4;Counter或者Timer:9 | ||||
|                 { | ||||
|                     Array.Copy(content, index2 + 4, dataArray, dataIndex, s7len); | ||||
|                     index2 += s7len + 3; | ||||
|                     dataIndex += s7len; | ||||
|                     index1++; | ||||
|                 } | ||||
|                 else if (content[index2] == byte.MaxValue && content[index2 + 1] == 9)//Counter或者Timer:9 | ||||
|                 { | ||||
|                     int num = (content[index2 + 2] * 256) + content[index2 + 3]; | ||||
|                     if (num % 3 == 0) | ||||
|                     { | ||||
|                         for (int index3 = 0; index3 < num / 3; index3++) | ||||
|                         { | ||||
|                             Array.Copy(content, index2 + 5 + (3 * index3), dataArray, dataIndex, 2); | ||||
|                             dataIndex += 2; | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         for (int index4 = 0; index4 < num / 5; index4++) | ||||
|                         { | ||||
|                             Array.Copy(content, index2 + 7 + (5 * index4), dataArray, dataIndex, 2); | ||||
|                             dataIndex += 2; | ||||
|                         } | ||||
|                     } | ||||
|                     index2 += num + 4; | ||||
|                     index1++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return new OperResult<byte[]>((int)content[index2] + GetCpuError(content[index2])); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return OperResult.CreateSuccessResult(dataArray); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     internal static OperResult<byte[]> AnalysisWrite(byte[] content) | ||||
|     { | ||||
|         if (content.Length < 22) | ||||
|         { | ||||
|             return new OperResult<byte[]>() { Message = "未知错误" }; | ||||
|         } | ||||
|  | ||||
|         byte err = content[21]; | ||||
|         if (err != byte.MaxValue) | ||||
|         { | ||||
|             return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21])); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return OperResult.CreateSuccessResult(content); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private static string GetCpuError(ushort Error) | ||||
|     { | ||||
|         return Error switch | ||||
|         { | ||||
|             0x05 => "地址超限", | ||||
|             0x06 => "返回长度无效", | ||||
|             0x07 => "数据大小不匹配", | ||||
|             0x0a or 0xd209 => "数据块不存在", | ||||
|             0x8500 => "超出PDU大小", | ||||
|             0xdc01 => "无效的值", | ||||
|             0x8104 => "功能不可用", | ||||
|             0xd241 => "需要密码", | ||||
|             0xd602 => "无效密码", | ||||
|             0xd604 or 0xd605 => "没有设置密码或已清除", | ||||
|             _ => "未知错误", | ||||
|         }; | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region 获取报文 | ||||
|     internal static OperResult<byte[]> GetReadCommand(SiemensAddress[] siemensAddress) | ||||
|     { | ||||
|         if (siemensAddress == null) | ||||
|         { | ||||
|             return new OperResult<byte[]>("地址为null"); | ||||
|         } | ||||
|         int len = siemensAddress.Length <= 19 ? siemensAddress.Length : throw new Exception("读取数量大于19!"); | ||||
|         int telegramLen = len * 12 + 19; | ||||
|         int parameterLen = len * 12 + 2; | ||||
|  | ||||
|         byte[] numArray = new byte[telegramLen]; | ||||
|  | ||||
|         Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length); | ||||
|         numArray[2] = (byte)(telegramLen / 256); | ||||
|         numArray[3] = (byte)(telegramLen % 256); | ||||
|         numArray[13] = (byte)(parameterLen / 256); | ||||
|         numArray[14] = (byte)(parameterLen % 256); | ||||
|         numArray[18] = (byte)len; | ||||
|  | ||||
|         for (int index = 0; index < len; index++) | ||||
|         { | ||||
|             Array.Copy(S7_MULRD_ITEM, 0, numArray, 19 + (index * 12), S7_MULRD_ITEM.Length); | ||||
|             if (siemensAddress[index].DataCode == (byte)S7WordLength.Counter || siemensAddress[index].DataCode == (byte)S7WordLength.Timer) | ||||
|             { | ||||
|                 numArray[22 + (index * 12)] = siemensAddress[index].DataCode; | ||||
|                 numArray[23 + (index * 12)] = (byte)(siemensAddress[index].Length / 256); | ||||
|                 numArray[24 + (index * 12)] = (byte)(siemensAddress[index].Length % 256); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 numArray[22 + (index * 12)] = (byte)S7WordLength.Byte; | ||||
|                 numArray[23 + (index * 12)] = (byte)(siemensAddress[index].Length / 256); | ||||
|                 numArray[24 + (index * 12)] = (byte)(siemensAddress[index].Length % 256); | ||||
|             } | ||||
|             numArray[25 + (index * 12)] = (byte)(siemensAddress[index].DbBlock / 256U); | ||||
|             numArray[26 + (index * 12)] = (byte)(siemensAddress[index].DbBlock % 256U); | ||||
|             numArray[27 + (index * 12)] = siemensAddress[index].DataCode; | ||||
|             numArray[28 + (index * 12)] = (byte)(siemensAddress[index].AddressStart / 256 / 256 % 256); | ||||
|             numArray[29 + (index * 12)] = (byte)(siemensAddress[index].AddressStart / 256 % 256); | ||||
|             numArray[30 + (index * 12)] = (byte)(siemensAddress[index].AddressStart % 256); | ||||
|         } | ||||
|         return OperResult.CreateSuccessResult(numArray); | ||||
|     } | ||||
|  | ||||
|     internal static OperResult<byte[]> GetWriteBitCommand(SiemensAddress address, bool data) | ||||
|     { | ||||
|         int len = 1; | ||||
|         int telegramLen = 16 + 19 + len;//最后的1是写入值的byte数量 | ||||
|         int parameterLen = 12 + 2; | ||||
|  | ||||
|         byte[] numArray = new byte[telegramLen]; | ||||
|  | ||||
|         Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length); | ||||
|         numArray[2] = (byte)(telegramLen / 256); | ||||
|         numArray[3] = (byte)(telegramLen % 256); | ||||
|         numArray[13] = (byte)(parameterLen / 256); | ||||
|         numArray[14] = (byte)(parameterLen % 256); | ||||
|         numArray[15] = (byte)((4 + len) / 256); | ||||
|         numArray[16] = (byte)((4 + len) % 256); | ||||
|         numArray[17] = 5; | ||||
|         numArray[18] = (byte)1; | ||||
|         //写入Item与读取大致相同 | ||||
|         numArray[19] = (byte)18; | ||||
|         numArray[20] = (byte)10; | ||||
|         numArray[21] = (byte)16; | ||||
|         numArray[22] = (byte)S7WordLength.Bit; | ||||
|         numArray[23] = (byte)(len / 256); | ||||
|         numArray[24] = (byte)(len % 256); | ||||
|         numArray[25] = (byte)(address.DbBlock / 256U); | ||||
|         numArray[26] = (byte)(address.DbBlock % 256U); | ||||
|         numArray[27] = (byte)address.DataCode; | ||||
|         numArray[28] = (byte)((address.AddressStart + address.BitCode) / 256 / 256); | ||||
|         numArray[29] = (byte)((address.AddressStart + address.BitCode) / 256); | ||||
|         numArray[30] = (byte)((address.AddressStart + address.BitCode) % 256); | ||||
|         //后面跟的是写入的数据信息 | ||||
|         numArray[31] = 0; | ||||
|         numArray[32] = 3;//Bit:3;Byte:4;Counter或者Timer:9 | ||||
|         numArray[33] = (byte)(len / 256); | ||||
|         numArray[34] = (byte)(len % 256); | ||||
|         numArray[35] = (byte)(data ? 1 : 0); | ||||
|  | ||||
|         return OperResult.CreateSuccessResult(numArray); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     internal static OperResult<byte[]> GetWriteByteCommand(SiemensAddress address, byte[] data) | ||||
|     { | ||||
|         int len = data.Length; | ||||
|         int telegramLen = 16 + 19 + len;//最后的1是写入值的byte数量 | ||||
|         int parameterLen = 12 + 2; | ||||
|  | ||||
|         byte[] numArray = new byte[telegramLen]; | ||||
|  | ||||
|         Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length); | ||||
|         numArray[2] = (byte)(telegramLen / 256); | ||||
|         numArray[3] = (byte)(telegramLen % 256); | ||||
|         numArray[13] = (byte)(parameterLen / 256); | ||||
|         numArray[14] = (byte)(parameterLen % 256); | ||||
|         numArray[15] = (byte)((4 + len) / 256); | ||||
|         numArray[16] = (byte)((4 + len) % 256); | ||||
|         numArray[17] = 5; | ||||
|         numArray[18] = (byte)1; | ||||
|         //写入Item与读取大致相同 | ||||
|         numArray[19] = (byte)18; | ||||
|         numArray[20] = (byte)10; | ||||
|         numArray[21] = (byte)16; | ||||
|         numArray[22] = (byte)S7WordLength.Byte; | ||||
|         numArray[23] = (byte)(len / 256); | ||||
|         numArray[24] = (byte)(len % 256); | ||||
|  | ||||
|         numArray[25] = (byte)(address.DbBlock / 256U); | ||||
|         numArray[26] = (byte)(address.DbBlock % 256U); | ||||
|         numArray[27] = (byte)address.DataCode; | ||||
|         numArray[28] = (byte)(address.AddressStart / 256 / 256); | ||||
|         numArray[29] = (byte)(address.AddressStart / 256); | ||||
|         numArray[30] = (byte)(address.AddressStart % 256); | ||||
|         //后面跟的是写入的数据信息 | ||||
|         numArray[31] = 0; | ||||
|         numArray[32] = 4;//Bit:3;Byte:4;Counter或者Timer:9 | ||||
|         numArray[33] = (byte)(len * 8 / 256); | ||||
|         numArray[34] = (byte)(len * 8 % 256); | ||||
|         data.CopyTo(numArray, 35); | ||||
|  | ||||
|         return OperResult.CreateSuccessResult(numArray); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region 字符串 | ||||
|  | ||||
|     internal static async Task<OperResult<string>> ReadStringAsync(SiemensS7PLC plc, string address, Encoding encoding, CancellationToken cancellationToken) | ||||
|     { | ||||
|         //先读取一次获取长度,再读取实际值 | ||||
|         if (plc.CurrentPlc != SiemensEnum.S200Smart) | ||||
|         { | ||||
|             var result1 = await plc.ReadAsync(address, 2, cancellationToken); | ||||
|             if (!result1.IsSuccess) | ||||
|             { | ||||
|                 return new(result1); | ||||
|             } | ||||
|             if (result1.Content[0] == (byte)0 || result1.Content[0] == byte.MaxValue) | ||||
|             { | ||||
|                 return new OperResult<string>("在PLC中不是字符串类型"); | ||||
|             } | ||||
|             var result2 = await plc.ReadAsync(address, 2 + result1.Content[1], cancellationToken); | ||||
|             if (!result2.IsSuccess) | ||||
|             { | ||||
|                 return new(result2); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 2, result2.Content.Length - 2)); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             var result1 = await plc.ReadAsync(address, 1, cancellationToken); | ||||
|             if (!result1.IsSuccess) | ||||
|                 return new(result1); | ||||
|             var result2 = await plc.ReadAsync(address, 1 + result1.Content[0], cancellationToken); | ||||
|             if (!result2.IsSuccess) | ||||
|             { | ||||
|                 return new(result2); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 1, result2.Content.Length - 1)); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     internal static async Task<OperResult> WriteAsync(SiemensS7PLC plc, string address, string value, Encoding encoding) | ||||
|     { | ||||
|         value ??= string.Empty; | ||||
|         byte[] inBytes = encoding.GetBytes(value); | ||||
|         //if (encoding == Encoding.Unicode) | ||||
|         //    inBytes = inBytes.BytesReverseByWord(); | ||||
|         if (plc.CurrentPlc != SiemensEnum.S200Smart) | ||||
|         { | ||||
|             OperResult<byte[]> result = await plc.ReadAsync(address, 2); | ||||
|             if (!result.IsSuccess) return result; | ||||
|             if (result.Content[0] == byte.MaxValue) return new OperResult<string>("在PLC中不是字符串类型"); | ||||
|             if (result.Content[0] == 0) result.Content[0] = 254; | ||||
|             if (value.Length > result.Content[0]) return new OperResult<string>("写入值长度超限"); | ||||
|             return await plc.WriteAsync( | ||||
|                 address, | ||||
|                 GenericExtensions.SpliceArray(new byte[2] { result.Content[0], (byte)value.Length }, | ||||
|                 inBytes | ||||
|                 )); | ||||
|         } | ||||
|         return await plc.WriteAsync(address, GenericExtensions.SpliceArray<byte>(new byte[1] | ||||
|         { | ||||
|     (byte) value.Length | ||||
|         }, inBytes)); | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public enum S7WordLength : byte | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     Bit = 0x01, | ||||
|     /// <inheritdoc/> | ||||
|     Byte = 0x02, | ||||
|     /// <inheritdoc/> | ||||
|     Char = 0x03, | ||||
|     /// <inheritdoc/> | ||||
|     Word = 0x04, | ||||
|     /// <inheritdoc/> | ||||
|     Int = 0x05, | ||||
|     /// <inheritdoc/> | ||||
|     DWord = 0x06, | ||||
|     /// <inheritdoc/> | ||||
|     DInt = 0x07, | ||||
|     /// <inheritdoc/> | ||||
|     Real = 0x08, | ||||
|     /// <inheritdoc/> | ||||
|     Counter = 0x1C, | ||||
|     /// <inheritdoc/> | ||||
|     Timer = 0x1D, | ||||
| } | ||||
| @@ -1,153 +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.Adapter.Siemens; | ||||
|  | ||||
| internal partial class SiemensHelper | ||||
| { | ||||
|     /// <summary> | ||||
|     /// S7连读写请求头(包含ISO头和COTP头)  | ||||
|     /// </summary> | ||||
|     static readonly byte[] S7_MULRW_HEADER = { | ||||
|             0x03,0x00, | ||||
|             0x00,0x1f,       // 报文长度(item.len*12+19,注意:根据传入读取item数量更改) | ||||
| 		0x02,0xf0, 0x80, //COTP信息 | ||||
| 		0x32,            // S7协议ID | ||||
| 		0x01,            // 类型,请求命令 | ||||
| 		0x00,0x00,       // 冗余识别 | ||||
| 		0x00,0x01,       // 序列号 | ||||
| 		0x00,0x0e,       // parameter长度(item.len*12+2,注意:根据传入读取item数量更改) | ||||
| 		0x00,0x00,       // Data Length+4 ,写入时填写,读取时为0   | ||||
| 		0x04,            //  4 Read Var, 5 Write Var  ,注意更改 | ||||
| 		0x01,            // Item数量(item.len,注意:根据传入读取item数量更改) | ||||
| 	}; | ||||
|  | ||||
|     // S7变量多读Item | ||||
|     static readonly byte[] S7_MULRD_ITEM = { | ||||
|             0x12,            // Var 规范. | ||||
| 		0x0a,            // 剩余的字节长度 | ||||
| 		0x10,            // Syntax ID  | ||||
| 		(byte)S7WordLength.Byte,  // 相关的数据长度代码(注意:根据传入的变量更改)                 | ||||
| 		0x00,0x01,       // 数据长度						(注意:根据传入的变量更改)       | ||||
| 		0x00,0x00,       // DB编号							(注意:根据传入的变量更改) | ||||
| 		0x84,            // 数据块类型					    (注意:根据传入的变量更改)           | ||||
| 		0x00,0x00,0x00   // 数据块偏移量			    (注意:根据传入的变量更改)               | ||||
| 	}; | ||||
|  | ||||
|  | ||||
|     // ISO连接请求报文(也包含ISO头和COTP头) | ||||
|     internal static byte[] ISO_CR = { | ||||
| 		// TPKT (RFC1006 Header) | ||||
| 		0x03, // RFC 1006 ID (3)  | ||||
| 		0x00, // 保留 0 | ||||
| 		0x00, // 数据包长度 (整个框架、有效载荷和TPDU包括在内) | ||||
| 		0x16, // 数据包长度 (整个框架、有效载荷和TPDU包括在内) | ||||
| 		// COTP (ISO 8073 Header) | ||||
| 		0x11, // PDU Size Length | ||||
| 		0xE0, // CR -连接请求ID | ||||
| 		0x00, 0x00, // Dst Reference | ||||
| 		0x00, 0x01, // Src Reference | ||||
| 		0x00, // Class + Options Flags | ||||
| 		//对于S7200/Smart ,下面参数也需要重写 | ||||
| 		0xC0, // PDU Max Length ID | ||||
| 		0x01, 0x0A, // PDU Max Length  | ||||
| 		0xC1, // Src TSAP Identifier | ||||
| 		0x02, // Src TSAP Length (2 bytes) | ||||
| 		0x01, 0x00, // Src TSAP  (需重写) | ||||
| 		0xC2, // Dst TSAP Identifier | ||||
| 		0x02, // Dst TSAP Length (2 bytes) | ||||
| 		0x01, 0x02  // Dst TSAP  (需重写) | ||||
| 	}; | ||||
|     // ISO连接请求报文(也包含ISO头和COTP头) | ||||
|     internal static byte[] ISO_CR200 = { | ||||
| 		// TPKT (RFC1006 Header) | ||||
| 		0x03, // RFC 1006 ID (3)  | ||||
| 		0x00, // 保留 0 | ||||
| 		0x00, // 数据包长度 (整个框架、有效载荷和TPDU包括在内) | ||||
| 		0x16, // 数据包长度 (整个框架、有效载荷和TPDU包括在内) | ||||
| 		// COTP (ISO 8073 Header) | ||||
| 		0x11, // PDU Size Length | ||||
| 		0xE0, // CR -连接请求ID | ||||
| 		0x00, 0x00, // Dst Reference | ||||
| 		0x00, 0x01, // Src Reference | ||||
| 		0x00, // Class + Options Flags | ||||
|  | ||||
| 		//对于S7200/Smart | ||||
| 		0xC1,0x02, | ||||
|             0x4D,0x57, //LOCALTASP | ||||
| 		0xC2, | ||||
|             0x02, | ||||
|             0x4D,0x57, //DESTTASP | ||||
| 		0xC0, | ||||
|             0x01,0x09 | ||||
|  | ||||
|         }; | ||||
|     // ISO连接请求报文(也包含ISO头和COTP头) | ||||
|     internal static byte[] ISO_CR200SMART = { | ||||
| 		// TPKT (RFC1006 Header) | ||||
| 		0x03, // RFC 1006 ID (3)  | ||||
| 		0x00, // 保留 0 | ||||
| 		0x00, // 数据包长度 (整个框架、有效载荷和TPDU包括在内) | ||||
| 		0x16, // 数据包长度 (整个框架、有效载荷和TPDU包括在内) | ||||
| 		// COTP (ISO 8073 Header) | ||||
| 		0x11, // PDU Size Length | ||||
| 		0xE0, // CR -连接请求ID | ||||
| 		0x00, 0x00, // Dst Reference | ||||
| 		0x00, 0x01, // Src Reference | ||||
| 		0x00, // Class + Options Flags | ||||
|  | ||||
| 		//对于S7200/Smart | ||||
| 		0xC1,0x02, | ||||
|             0x10,0x00,//LOCALTASP | ||||
| 		0xC2, | ||||
|             0x02, | ||||
|             0x03,0x00,//DESTTASP | ||||
| 		0xC0, | ||||
|             0x01,0x0A | ||||
|         }; | ||||
|     // PDU获取报文(也包含ISO头和COTP头) | ||||
|     internal static byte[] S7_PN = { | ||||
|             0x03, 0x00, 0x00, 0x19, | ||||
|             0x02, 0xf0, 0x80, // TPKT + COTP | ||||
| 		0x32, 0x01, 0x00, 0x00, | ||||
|  | ||||
| 		//这里对于S7200/Smart需要重写 | ||||
|             0x04, 0x00, 0x00, 0x08, | ||||
|  | ||||
|             0x00, 0x00, 0xf0, 0x00, | ||||
|             0x00, 0x01, 0x00, 0x01, | ||||
|             0x01,0xE0        // PDU Length Requested  这里默认480字节,对于S7200/Smart 960字节 | ||||
| 	}; | ||||
|     // PDU获取报文(也包含ISO头和COTP头) | ||||
|     internal static byte[] S7200_PN = { | ||||
|             0x03, 0x00, 0x00, 0x19, | ||||
|             0x02, 0xf0, 0x80, // TPKT + COTP | ||||
| 		0x32, 0x01, 0x00, 0x00, | ||||
|  | ||||
|             0x00,0x00,0x00,0x08, | ||||
|  | ||||
|             0x00, 0x00, 0xf0, 0x00, | ||||
|             0x00, 0x01, 0x00, 0x01, | ||||
|             0x01,0xE0        // PDU Length Requested  这里默认960字节 | ||||
| 	}; | ||||
|     internal static byte[] S7200SMART_PN = { | ||||
|             0x03, 0x00, 0x00, 0x19, | ||||
|             0x02, 0xf0, 0x80, // TPKT + COTP | ||||
| 		0x32, 0x01, 0x00, 0x00, | ||||
|  | ||||
|             0xCC,0xC1,0x00,0x08, | ||||
|  | ||||
|             0x00, 0x00, 0xf0, 0x00, | ||||
|             0x00, 0x01, 0x00, 0x01, | ||||
|             0x01,0xE0        // PDU Length Requested  这里默认960字节 | ||||
| 	}; | ||||
| } | ||||
| @@ -1,37 +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.Adapter.Siemens; | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class SiemensMessage : MessageBase, IMessage | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public override int HeadBytesLength => 4; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override bool CheckHeadBytes(byte[] heads) | ||||
|     { | ||||
|         HeadBytes = heads; | ||||
|         byte[] headBytes = HeadBytes; | ||||
|         if (headBytes == null || headBytes.Length < 4) | ||||
|             BodyLength = 0; | ||||
|         int length = (HeadBytes[2] * 256) + HeadBytes[3] - 4; | ||||
|         if (length < 0) | ||||
|             length = 0; | ||||
|         BodyLength = length; | ||||
|         return HeadBytes != null && HeadBytes[0] == 3 && HeadBytes[1] == 0; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,34 +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.Adapter.Siemens; | ||||
| /// <summary> | ||||
| /// <inheritdoc/> | ||||
| /// </summary> | ||||
| public enum SiemensEnum | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     S200, | ||||
|     /// <inheritdoc/> | ||||
|     S200Smart, | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     S300, | ||||
|     /// <inheritdoc/> | ||||
|     S400, | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     S1200, | ||||
|     /// <inheritdoc/> | ||||
|     S1500, | ||||
|  | ||||
| } | ||||
| @@ -1,505 +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.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
| using ThingsGateway.Foundation.Extension.String; | ||||
|  | ||||
| namespace ThingsGateway.Foundation.Adapter.Siemens | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 相关命令含义源自网络资料/Shrap7/s7netplus | ||||
|     /// </summary> | ||||
|     public partial class SiemensS7PLC : ReadWriteDevicesTcpClientBase | ||||
|     { | ||||
|         private readonly SiemensEnum _currentPlc = SiemensEnum.S1200; | ||||
|         private readonly byte[] ISO_CR; | ||||
|         private readonly byte[] S7_PN; | ||||
|         private int pdu_length = 100; | ||||
|         private byte plc_rack = 0; | ||||
|         private byte plc_slot = 0; | ||||
|         /// <summary> | ||||
|         /// 传入PLC类型,程序内会改变相应PLC类型的S7协议LocalTSAP, RemoteTSAP等 | ||||
|         /// </summary> | ||||
|         /// <param name="tcpClient"></param> | ||||
|         /// <param name="siemensPLCEnum"></param> | ||||
|         public SiemensS7PLC(TcpClient tcpClient, SiemensEnum siemensPLCEnum) : base(tcpClient) | ||||
|         { | ||||
|             _currentPlc = siemensPLCEnum; | ||||
|             RegisterByteLength = 1; | ||||
|             ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big); | ||||
|             ISO_CR = new byte[22]; | ||||
|             S7_PN = new byte[25]; | ||||
|             Array.Copy(SiemensHelper.ISO_CR, ISO_CR, ISO_CR.Length); | ||||
|             Array.Copy(SiemensHelper.S7_PN, S7_PN, S7_PN.Length); | ||||
|             switch (siemensPLCEnum) | ||||
|             { | ||||
|                 case SiemensEnum.S1200: | ||||
|                     ISO_CR[21] = 0x00; | ||||
|                     break; | ||||
|                 case SiemensEnum.S300: | ||||
|                     ISO_CR[21] = 0x02; | ||||
|                     break; | ||||
|                 case SiemensEnum.S400: | ||||
|                     ISO_CR[21] = 0x03; | ||||
|                     ISO_CR[17] = 0x00; | ||||
|                     break; | ||||
|                 case SiemensEnum.S1500: | ||||
|                     ISO_CR[21] = 0x00; | ||||
|                     break; | ||||
|                 case SiemensEnum.S200Smart: | ||||
|                     ISO_CR = SiemensHelper.ISO_CR200SMART; | ||||
|                     S7_PN = SiemensHelper.S7200SMART_PN; | ||||
|                     break; | ||||
|                 case SiemensEnum.S200: | ||||
|                     ISO_CR = SiemensHelper.ISO_CR200; | ||||
|                     S7_PN = SiemensHelper.S7200_PN; | ||||
|                     break; | ||||
|  | ||||
|             } | ||||
|             tcpClient.Connected += Connected; | ||||
|  | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 当前PLC类型 | ||||
|         /// </summary> | ||||
|         public SiemensEnum CurrentPlc => _currentPlc; | ||||
|         /// <inheritdoc/> | ||||
|         public override string GetAddressDescription() | ||||
|         { | ||||
|             StringBuilder stringBuilder = new(); | ||||
|             stringBuilder.AppendLine("S7协议寄存器地址格式"); | ||||
|             stringBuilder.AppendLine("Txxxxx	Timer寄存器,例如T100/T100.1"); | ||||
|             stringBuilder.AppendLine("Cxxxxx,Counter寄存器,例如C100/C100.1"); | ||||
|             stringBuilder.AppendLine("AIxxxxx,AI寄存器,例如AI100/AI100.1"); | ||||
|             stringBuilder.AppendLine("AQxxxxx,AQ寄存器,例如AQ100/AQ100.1"); | ||||
|             stringBuilder.AppendLine("Ixxxxx,I寄存器,例如I100/I100.1"); | ||||
|             stringBuilder.AppendLine("Qxxxxx,Q寄存器,例如Q100/Q100.1"); | ||||
|             stringBuilder.AppendLine("Mxxxxx,M寄存器,例如M100/M100.1"); | ||||
|             stringBuilder.AppendLine("DBxxxxx,DB寄存器,例如DB100.1/DB100.1.1"); | ||||
|             stringBuilder.AppendLine(""); | ||||
|  | ||||
|             return base.GetAddressDescription() + Environment.NewLine + stringBuilder.ToString(); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// <inheritdoc/> | ||||
|         /// </summary> | ||||
|         /// <param name="address"></param> | ||||
|         /// <returns></returns> | ||||
|         public override int GetBitOffset(string address) | ||||
|         { | ||||
|             if (address.IndexOf('.') > 0) | ||||
|             { | ||||
|                 string[] addressSplits = address.SplitDot(); | ||||
|                 try | ||||
|                 { | ||||
|                     int bitIndex = 0; | ||||
|                     if ((addressSplits.Length == 2 && !address.ToUpper().Contains("DB")) || (addressSplits.Length >= 3 && address.ToUpper().Contains("DB"))) | ||||
|                         bitIndex = Convert.ToInt32(addressSplits.Last()); | ||||
|                     return bitIndex; | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     return 0; | ||||
|                 } | ||||
|             } | ||||
|             return 0; | ||||
|         } | ||||
|         /// <inheritdoc/> | ||||
|         public override bool IsBitReverse(string address) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         #region 设置 | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 远程TSAP,需重新连接 | ||||
|         /// </summary> | ||||
|         public int DestTSAP | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return | ||||
|                     _currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart ? | ||||
|                     (ISO_CR[17] * 256) + ISO_CR[18] : | ||||
|                     (ISO_CR[20] * 256) + ISO_CR[21]; | ||||
|             } | ||||
|             set | ||||
|             { | ||||
|                 if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart) | ||||
|                 { | ||||
|                     ISO_CR[17] = BitConverter.GetBytes(value)[1]; | ||||
|                     ISO_CR[18] = BitConverter.GetBytes(value)[0]; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ISO_CR[20] = BitConverter.GetBytes(value)[1]; | ||||
|                     ISO_CR[21] = BitConverter.GetBytes(value)[0]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 本地TSAP,需重新连接 | ||||
|         /// </summary> | ||||
|         public int LocalTSAP | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return | ||||
|                     _currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart ? | ||||
|                     (ISO_CR[13] * 256) + ISO_CR[14] : | ||||
|                     (ISO_CR[16] * 256) + ISO_CR[17]; | ||||
|             } | ||||
|             set | ||||
|             { | ||||
|                 if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart) | ||||
|                 { | ||||
|                     ISO_CR[13] = BitConverter.GetBytes(value)[1]; | ||||
|                     ISO_CR[14] = BitConverter.GetBytes(value)[0]; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ISO_CR[16] = BitConverter.GetBytes(value)[1]; | ||||
|                     ISO_CR[17] = BitConverter.GetBytes(value)[0]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// PDULength | ||||
|         /// </summary> | ||||
|         public int PDULength => pdu_length; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 机架号,需重新连接 | ||||
|         /// </summary> | ||||
|         public byte Rack | ||||
|         { | ||||
|             get => plc_rack; | ||||
|             set | ||||
|             { | ||||
|                 plc_rack = value; | ||||
|                 if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 ISO_CR[21] = (byte)((plc_rack * 0x20) + plc_slot); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 槽号,需重新连接 | ||||
|         /// </summary> | ||||
|         public byte Slot | ||||
|         { | ||||
|             get => plc_slot; | ||||
|             set | ||||
|             { | ||||
|                 plc_slot = value; | ||||
|                 if (_currentPlc == SiemensEnum.S200 || _currentPlc == SiemensEnum.S200Smart) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|                 ISO_CR[21] = (byte)((plc_rack * 0x20) + plc_slot); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         #endregion | ||||
|  | ||||
|         /// <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 = GetReadByteCommand(address, length); | ||||
|                 if (commandResult.IsSuccess) | ||||
|                 { | ||||
|                     List<byte> bytes = new(); | ||||
|                     foreach (var item in commandResult.Content) | ||||
|                     { | ||||
|                         var result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|                         if (((MessageBase)result.RequestInfo).IsSuccess) | ||||
|                             bytes.AddRange(((MessageBase)result.RequestInfo).Content); | ||||
|                         else | ||||
|                             return new(((MessageBase)result.RequestInfo)); | ||||
|                     } | ||||
|                     return OperResult.CreateSuccessResult(bytes.ToArray()); | ||||
|                 } | ||||
|  | ||||
|                 else | ||||
|                 { | ||||
|                     return new(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 = GetReadByteCommand(address, length); | ||||
|                 if (commandResult.IsSuccess) | ||||
|                 { | ||||
|                     List<byte> bytes = new(); | ||||
|                     foreach (var item in commandResult.Content) | ||||
|                     { | ||||
|                         var result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|                         if (((MessageBase)result.RequestInfo).IsSuccess) | ||||
|                             bytes.AddRange(((MessageBase)result.RequestInfo).Content); | ||||
|                         else | ||||
|                             return new(((MessageBase)result.RequestInfo)); | ||||
|                     } | ||||
|                     return OperResult.CreateSuccessResult(bytes.ToArray()); | ||||
|                 } | ||||
|  | ||||
|                 else | ||||
|                 { | ||||
|                     return new(commandResult); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<byte[]>(ex); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override void SetDataAdapter(object socketClient = null) | ||||
|         { | ||||
|             SiemensS7PLCDataHandleAdapter DataHandleAdapter = new(); | ||||
|             TcpClient.SetDataHandlingAdapter(DataHandleAdapter); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override OperResult Write(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 Connect(cancellationToken); | ||||
|                 var commandResult = GetWriteByteCommand(address, value); | ||||
|                 if (commandResult.IsSuccess) | ||||
|                 { | ||||
|                     List<ResponsedData> bytes = new(); | ||||
|                     foreach (var item in commandResult.Content) | ||||
|                     { | ||||
|                         ResponsedData result = WaitingClientEx.SendThenResponse(item, TimeOut, cancellationToken); | ||||
|                         if (!((MessageBase)result.RequestInfo).IsSuccess) | ||||
|                             return new(((MessageBase)result.RequestInfo)); | ||||
|                         bytes.Add(result); | ||||
|                     } | ||||
|                     return OperResult.CreateSuccessResult(bytes.ToArray()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return new(commandResult); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<bool[]>(ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override OperResult Write(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|         { | ||||
|             if (value.Length > 1) | ||||
|             { | ||||
|                 return new OperResult("不支持多写"); | ||||
|             } | ||||
|             try | ||||
|             { | ||||
|                 Connect(cancellationToken); | ||||
|  | ||||
|                 var commandResult = GetWriteBitCommand(address, value[0]); | ||||
|                 if (commandResult.IsSuccess) | ||||
|                 { | ||||
|                     var result = WaitingClientEx.SendThenResponse(commandResult.Content, TimeOut, cancellationToken); | ||||
|                     return (MessageBase)result.RequestInfo; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return new(commandResult); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<bool[]>(ex); | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override Task<OperResult> WriteAsync(string address, string value, CancellationToken cancellationToken = default) | ||||
|         { | ||||
|             IThingsGatewayBitConverter transformParameter = ByteTransformUtil.GetTransByAddress(ref address, ThingsGatewayBitConverter); | ||||
|             return SiemensHelper.WriteAsync(this, address, value, transformParameter.Encoding); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override async Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 await ConnectAsync(cancellationToken); | ||||
|                 var commandResult = GetWriteByteCommand(address, value); | ||||
|                 if (commandResult.IsSuccess) | ||||
|                 { | ||||
|                     List<ResponsedData> bytes = new(); | ||||
|                     foreach (var item in commandResult.Content) | ||||
|                     { | ||||
|                         ResponsedData result = await WaitingClientEx.SendThenResponseAsync(item, TimeOut, cancellationToken); | ||||
|                         if (!((MessageBase)result.RequestInfo).IsSuccess) | ||||
|                             return new(((MessageBase)result.RequestInfo)); | ||||
|                         bytes.Add(result); | ||||
|                     } | ||||
|                     return OperResult.CreateSuccessResult(bytes.ToArray()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return new(commandResult); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<bool[]>(ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override async Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default) | ||||
|         { | ||||
|             if (value.Length > 1) | ||||
|             { | ||||
|                 return new OperResult("不支持多写"); | ||||
|             } | ||||
|             try | ||||
|             { | ||||
|                 await ConnectAsync(cancellationToken); | ||||
|  | ||||
|                 var commandResult = GetWriteBitCommand(address, value[0]); | ||||
|                 if (commandResult.IsSuccess) | ||||
|                 { | ||||
|                     var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, cancellationToken); | ||||
|                     return (MessageBase)result.RequestInfo; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return new(commandResult); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult<bool[]>(ex); | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         #region 其他方法 | ||||
|         /// <summary> | ||||
|         /// 读取日期 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public async Task<OperResult<System.DateTime>> ReadDateAsync(string address, CancellationToken cancellationToken) | ||||
|         { | ||||
|             return (await this.ReadAsync(address, 2, cancellationToken)). | ||||
|                  Then(m => OperResult.CreateSuccessResult(ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMinimumDateTime.AddDays( | ||||
|                      ThingsGatewayBitConverter.ToUInt16(m, 0))) | ||||
|                  ); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 读取时间 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public async Task<OperResult<System.DateTime>> ReadDateTimeAsync(string address, CancellationToken cancellationToken) | ||||
|         { | ||||
|             return ByteTransformUtil.GetResultFromBytes(await ReadAsync(address, 8, cancellationToken), ThingsGateway.Foundation.Adapter.Siemens.DateTime.FromByteArray); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 读取变长字符串 | ||||
|         /// </summary> | ||||
|         public async Task<OperResult<string>> ReadStringAsync(string address, Encoding encoding, CancellationToken cancellationToken) | ||||
|         { | ||||
|             return await SiemensHelper.ReadStringAsync(this, address, encoding, cancellationToken); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// 写入日期 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public async Task<OperResult> WriteDateAsync(string address, System.DateTime dateTime, CancellationToken cancellationToken) | ||||
|         { | ||||
|             return await base.WriteAsync(address, Convert.ToUInt16((dateTime - ThingsGateway.Foundation.Adapter.Siemens.DateTime.SpecMinimumDateTime).TotalDays), cancellationToken); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 写入时间 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public async Task<OperResult> WriteDateTimeAsync(string address, System.DateTime dateTime, CancellationToken cancellationToken) | ||||
|         { | ||||
|             return await WriteAsync(address, ThingsGateway.Foundation.Adapter.Siemens.DateTime.ToByteArray(dateTime), cancellationToken); | ||||
|         } | ||||
|         #endregion | ||||
|  | ||||
|         private void Connected(ITcpClient client, ConnectedEventArgs e) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 var result1 = SendThenResponse(ISO_CR); | ||||
|                 if (!result1.IsSuccess) | ||||
|                 { | ||||
|                     Logger?.Warning($"{client.IP} : {client.Port}:ISO_TP握手失败-{result1.Message}"); | ||||
|                     return; | ||||
|                 } | ||||
|                 var result2 = SendThenResponse(S7_PN); | ||||
|                 if (!result2.IsSuccess) | ||||
|                 { | ||||
|                     Logger?.Warning($"{client.IP} : {client.Port}:PDU初始化失败-{result2.Message}"); | ||||
|                     return; | ||||
|                 } | ||||
|                 pdu_length = ThingsGatewayBitConverter.ToUInt16(result2.Content.SelectLast(2), 0); | ||||
|                 pdu_length = pdu_length < 200 ? 200 : pdu_length; | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 Logger.Exception(ex); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,61 +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.Adapter.Siemens; | ||||
|  | ||||
| /// <summary> | ||||
| /// SiemensS7PLCDataHandleAdapter | ||||
| /// </summary> | ||||
| public class SiemensS7PLCDataHandleAdapter : ReadWriteDevicesTcpDataHandleAdapter<SiemensMessage> | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public override byte[] PackCommand(byte[] command) | ||||
|     { | ||||
|         return command; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     protected override SiemensMessage GetInstance() | ||||
|     { | ||||
|         return new SiemensMessage(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override FilterResult UnpackResponse(SiemensMessage request, byte[] send, byte[] body, byte[] response) | ||||
|     { | ||||
|         var result = new OperResult<byte[]>(); | ||||
|         if (response[2] * 256 + response[3] == 7) | ||||
|         { | ||||
|             result = new OperResult<byte[]>() { Content = response }; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             //以请求方为准,分开返回类型校验 | ||||
|             switch (send[17]) | ||||
|             { | ||||
|                 case 0x04: | ||||
|                     result = SiemensHelper.AnalysisReadByte(send, response); | ||||
|                     break; | ||||
|                 case 0x05: | ||||
|                     result = SiemensHelper.AnalysisWrite(response); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|         request.ErrorCode = result.ErrorCode; | ||||
|         request.Message = result.Message; | ||||
|         request.Content = result.Content; | ||||
|         return FilterResult.Success; | ||||
|     } | ||||
| } | ||||
| @@ -1,129 +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.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,5 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 	<ItemGroup> | ||||
| 		<ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> | ||||
| 	</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