@@ -29,7 +29,7 @@ public class S7CommPlusConnection
2929 private MemoryStream m_ReceivedStream ;
3030 private bool m_ReceivedNeedMorePdus ;
3131 private bool m_NewS7CommPlusReceived ;
32-
32+
3333 private UInt32 m_SessionId ;
3434 private int m_ReadTimeout = 5000 ;
3535
@@ -47,7 +47,7 @@ public class S7CommPlusConnection
4747
4848 #region Public Members
4949 public int m_LastError = 0 ;
50-
50+
5151 #endregion
5252
5353 #region Private Methods
@@ -90,12 +90,13 @@ private void WaitForNewS7plusReceived(int Timeout)
9090 Thread . Sleep ( 2 ) ;
9191 Expired = Environment . TickCount - Elapsed > Timeout ;
9292 }
93-
93+
9494 if ( Expired )
9595 {
9696 Console . WriteLine ( "S7CommPlusConnection - WaitForNewS7plusReceived: FEHLER: Timeout!" ) ;
9797 m_LastError = S7Consts . errTCPDataReceive ;
98- } else
98+ }
99+ else
99100 {
100101 // Console.WriteLine("S7CommPlusConnection - WaitForNewS7plusReceived: ...neue S7CommPlusPDU vollständig empfangen. Zeit: " + (Environment.TickCount - Elapsed) + " ms.");
101102 }
@@ -339,7 +340,7 @@ private int checkResponseWithIntegrity(object responseObject, UInt16 requestSequ
339340 // Hier kann ein Overflow vorkommen, ist aber erlaubt und Ergebnis wird akzeptiert.
340341 UInt32 reqIntegCheck = ( UInt32 ) requestSequenceNumber + requestIntegrity ;
341342 if ( responseIntegrity != reqIntegCheck )
342- {
343+ {
343344 Console . WriteLine ( String . Format ( "checkResponseWithIntegrity: FEHLER! Integrity der Response ({0}) passt nicht zum Request ({1})" , responseIntegrity , reqIntegCheck ) ) ;
344345 // Vorerst nicht als Fehler zurückgeben
345346 }
@@ -377,7 +378,7 @@ public int Connect(string address)
377378 return res ;
378379
379380 #region Schritt 1: Unverschlüsselt InitSSL Request / Response
380-
381+
381382 // Ab jetzt den Thread starten
382383 InitSslRequest sslrequest = new InitSslRequest ( ProtocolVersion . V1 , GetNextSequenceNumber ( ) , 0 ) ;
383384 res = SendS7plusFunctionObject ( sslrequest ) ;
@@ -454,7 +455,7 @@ public int Connect(string address)
454455 #endregion
455456
456457 #region Schritt 4: SetMultiVariablesRequest / Response
457-
458+
458459 SetMultiVariablesRequest setMultiVariablesRequest = new SetMultiVariablesRequest ( ProtocolVersion . V2 ) ;
459460 setMultiVariablesRequest . SetSessionSetupData ( m_SessionId , serverSession ) ;
460461 setMultiVariablesRequest . SequenceNumber = GetNextSequenceNumber ( ) ;
@@ -539,7 +540,7 @@ public int ReadValues(List<ItemAddress> addresslist, out List<object> values, ou
539540 getMultiVariablesRequest . AddressList . Clear ( ) ;
540541 count_perChunk = 0 ;
541542 while ( count_perChunk < m_MaxTagsPerReadRequestLimit && ( chunk_startIndex + count_perChunk ) < addresslist . Count )
542- {
543+ {
543544 getMultiVariablesRequest . AddressList . Add ( addresslist [ chunk_startIndex + count_perChunk ] ) ;
544545 count_perChunk ++ ;
545546 }
@@ -580,7 +581,7 @@ public int ReadValues(List<ItemAddress> addresslist, out List<object> values, ou
580581
581582 foreach ( var ev in getMultiVariablesResponse . ErrorValues )
582583 {
583- errors [ chunk_startIndex + ( int ) ev . Key - 1 ] = ev . Value ;
584+ errors [ chunk_startIndex + ( int ) ev . Key - 1 ] = ev . Value ;
584585 }
585586
586587 chunk_startIndex += count_perChunk ;
@@ -733,7 +734,7 @@ public int Browse(out List<VarInfo> varInfoList)
733734 #endregion
734735
735736 #region Alle Datenbausteine auswerten die anschließend gebrowst werden müssen
736-
737+
737738 List < PObject > objList = exploreRes . ResponseObject . GetObjects ( ) ;
738739
739740 foreach ( var ob in objList )
@@ -869,7 +870,7 @@ public int Browse(out List<VarInfo> varInfoList)
869870 else
870871 {
871872 List < PObject > objs = exploreResponse . ResponseObject . GetObjectsByClassId ( Ids . ClassTypeInfo ) ;
872-
873+
873874 vars . SetTypeInfoContainerObjects ( objs ) ;
874875 vars . BuildTree ( ) ;
875876 vars . BuildFlatList ( ) ;
@@ -897,6 +898,189 @@ public class BrowseData
897898 public UInt32 db_block_ti_relid ; // Type-Info RID des Datenbausteins
898899 public List < BrowseEntry > variables = new List < BrowseEntry > ( ) ; // Variablen des Datenbausteins
899900 } ;
900- #endregion
901+
902+
903+ public class DatablockInfo
904+ {
905+ public string db_name ; // Name of the datablock
906+ public UInt32 db_number ; // Number of the datablock
907+ public UInt32 db_block_relid ; // RID of the datablock
908+ public UInt32 db_block_ti_relid ; // Type-Info RID of the datablock
909+ } ;
910+
911+ public int GetListOfDatablocks ( out List < DatablockInfo > dbInfoList )
912+ {
913+ int res ;
914+
915+ dbInfoList = new List < DatablockInfo > ( ) ;
916+
917+ var exploreReq = new ExploreRequest ( ProtocolVersion . V2 ) ;
918+ exploreReq . SessionId = m_SessionId ;
919+ exploreReq . SequenceNumber = GetNextSequenceNumber ( ) ;
920+ exploreReq . ExploreId = Ids . NativeObjects_thePLCProgram_Rid ;
921+ exploreReq . ExploreRequestId = Ids . None ;
922+ exploreReq . ExploreChildsRecursive = 1 ;
923+ exploreReq . ExploreParents = 0 ;
924+ exploreReq . IntegrityId = GetNextIntegrityId ( ) ;
925+
926+ // Add the attributes we need in the response
927+ exploreReq . AddressList . Add ( Ids . ObjectVariableTypeName ) ;
928+
929+ // Set filter on Id for Datablock Class RID. With this filter, we only
930+ // get informations from datablocks, and not other blocks we don't need here.
931+ var filter = new ValueStruct ( Ids . Filter ) ;
932+ filter . AddStructElement ( Ids . FilterOperation , new ValueDInt ( 8 ) ) ; // 8 = InstanceIOf
933+ filter . AddStructElement ( Ids . AddressCount , new ValueUDInt ( 0 ) ) ;
934+ uint [ ] faddress = new uint [ 32 ] ; // Unknown, possible dependant on FilterOperation
935+ filter . AddStructElement ( Ids . Address , new ValueUDIntArray ( faddress ) ) ;
936+ filter . AddStructElement ( Ids . FilterValue , new ValueRID ( Ids . DB_Class_Rid ) ) ;
937+
938+ exploreReq . FilterData = filter ;
939+
940+ res = SendS7plusFunctionObject ( exploreReq ) ;
941+ if ( res != 0 )
942+ {
943+ return res ;
944+ }
945+ m_LastError = 0 ;
946+ WaitForNewS7plusReceived ( m_ReadTimeout ) ;
947+ if ( m_LastError != 0 )
948+ {
949+ return m_LastError ;
950+ }
951+
952+ var exploreRes = ExploreResponse . DeserializeFromPdu ( m_ReceivedStream , true ) ;
953+ res = checkResponseWithIntegrity ( exploreRes ,
954+ exploreReq . SequenceNumber ,
955+ exploreRes . SequenceNumber ,
956+ exploreReq . IntegrityId ,
957+ exploreRes . IntegrityId ) ;
958+ if ( res != 0 )
959+ {
960+ return res ;
961+ }
962+
963+ // Get the datablock information we want further informations from.
964+ var objList = exploreRes . ResponseObject . GetObjects ( ) ;
965+
966+ foreach ( var ob in objList )
967+ {
968+ // May be this check can be removed, if setting the filter to the DB_Class_Rid is working 100%.
969+ switch ( ob . ClassId )
970+ {
971+ case Ids . DB_Class_Rid :
972+ UInt32 relid = ob . RelationId ;
973+ UInt32 area = ( relid >> 16 ) ;
974+ UInt32 num = relid & 0xffff ;
975+ if ( area == 0x8a0e )
976+ {
977+ var name = ( ValueWString ) ( ob . GetAttribute ( Ids . ObjectVariableTypeName ) ) ;
978+ DatablockInfo data = new DatablockInfo ( ) ;
979+ data . db_block_relid = relid ;
980+ data . db_name = name . GetValue ( ) ;
981+ data . db_number = num ;
982+ dbInfoList . Add ( data ) ;
983+ }
984+ break ;
985+ }
986+ }
987+
988+ // Get the TypeInfo RID to RelId from the first response
989+
990+ // With LID=1 we get the RID back. With this number we can explore further
991+ // informations of this datablock.
992+ // This is neccessary, because informations about instance DBs (e.g. TON) you
993+ // don't get by the RID of the DB, instead of exploring the TON Type RID.
994+ var readlist = new List < ItemAddress > ( ) ;
995+ var values = new List < object > ( ) ;
996+ var errors = new List < UInt64 > ( ) ;
997+
998+ foreach ( var data in dbInfoList )
999+ {
1000+ if ( data . db_number > 0 )
1001+ {
1002+ // Insert the address
1003+ var adr1 = new ItemAddress ( ) ;
1004+ adr1 . AccessArea = data . db_block_relid ;
1005+ adr1 . AccessSubArea = Ids . DB_ValueActual ;
1006+ adr1 . LID . Add ( 1 ) ;
1007+ readlist . Add ( adr1 ) ;
1008+ }
1009+ }
1010+ res = ReadValues ( readlist , out values , out errors ) ;
1011+ if ( res != 0 )
1012+ {
1013+ return res ;
1014+ }
1015+
1016+ // Insert response data into the list
1017+ for ( int i = 0 ; i < values . Count ; i ++ )
1018+ {
1019+ if ( errors [ i ] == 0 )
1020+ {
1021+ var rid = ( ValueRID ) values [ i ] ;
1022+ var data = dbInfoList [ i ] ;
1023+ data . db_block_ti_relid = rid . GetValue ( ) ;
1024+ dbInfoList [ i ] = data ;
1025+ }
1026+ else
1027+ {
1028+ // On error, set relid=0, which is then removed in the next step
1029+ // Should we report this for the user?
1030+ var data = dbInfoList [ i ] ;
1031+ data . db_block_ti_relid = 0 ;
1032+ dbInfoList [ i ] = data ;
1033+ }
1034+ }
1035+
1036+ // Remove elements with db_block_ti_relid == 0.
1037+ // This can occur on datablocks which are only in load memory, and can't be explored.
1038+ dbInfoList . RemoveAll ( item => item . db_block_ti_relid == 0 ) ;
1039+
1040+ return 0 ;
1041+ }
1042+
1043+
1044+ public int GetTypeInformation ( uint exploreId , out List < PObject > objList )
1045+ {
1046+ int res ;
1047+ objList = new List < PObject > ( ) ;
1048+
1049+ var exploreReq = new ExploreRequest ( ProtocolVersion . V2 ) ;
1050+ exploreReq . SessionId = m_SessionId ;
1051+ exploreReq . SequenceNumber = GetNextSequenceNumber ( ) ;
1052+ exploreReq . IntegrityId = GetNextIntegrityId ( ) ;
1053+ exploreReq . ExploreId = exploreId ;
1054+ exploreReq . ExploreRequestId = Ids . None ;
1055+ exploreReq . ExploreChildsRecursive = 1 ;
1056+ exploreReq . ExploreParents = 0 ;
1057+
1058+ res = SendS7plusFunctionObject ( exploreReq ) ;
1059+ if ( res != 0 )
1060+ {
1061+ return res ;
1062+ }
1063+ m_LastError = 0 ;
1064+ WaitForNewS7plusReceived ( m_ReadTimeout ) ;
1065+ if ( m_LastError != 0 )
1066+ {
1067+ return m_LastError ;
1068+ }
1069+
1070+ var exploreRes = ExploreResponse . DeserializeFromPdu ( m_ReceivedStream , true ) ;
1071+ res = checkResponseWithIntegrity ( exploreRes ,
1072+ exploreReq . SequenceNumber ,
1073+ exploreRes . SequenceNumber ,
1074+ exploreReq . IntegrityId ,
1075+ exploreRes . IntegrityId ) ;
1076+ if ( res != 0 )
1077+ {
1078+ return res ;
1079+ }
1080+ objList . Add ( exploreRes . ResponseObject ) ;
1081+
1082+ return 0 ;
1083+ }
9011084 }
1085+ #endregion
9021086}
0 commit comments