rllib  1
Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
rlSiemensTCP Class Reference

#include <rlsiemenstcp.h>

Inheritance diagram for rlSiemensTCP:
Inheritance graph
[legend]
Collaboration diagram for rlSiemensTCP:
Collaboration graph
[legend]

Classes

struct  FA
 
struct  FH
 
struct  IH
 
struct  WA
 
struct  WH
 

Public Types

enum  ORG {
  ORG_DB = 1, ORG_M = 2, ORG_E = 3, ORG_A = 4,
  ORG_PEPA = 5, ORG_Z = 6, ORG_T = 7
}
 
enum  PLC_TYPE {
  ANY_SIEMENS_COMPATIBLE_PLC = 1000, S7_200 = 1, S7_300 = 2, S7_400 = 3,
  S5 = 4, RACK_SLOT = 5, S7_1200 = 6, LOGO = 7
}
 
enum  SiemensFunctionCodes { WriteBit = 1, WriteByte = 2 }
 
- Public Types inherited from rlSocket
enum  SocketEnum {
  SOCKET_ERR = -1, SETSOCKOPT_ERR = -2, LISTEN_ERR = -3, ACCEPT_ERR = -4,
  INET_ADDR_ERR = -5, CONNECT_ERR = -6, PORT_ERR = -7
}
 

Public Member Functions

 rlSiemensTCP (const char *adr, int _plc_type=rlSiemensTCP::ANY_SIEMENS_COMPATIBLE_PLC, int _fetch_write=1, int function=-1, int rack_slot=-1)
 
virtual ~rlSiemensTCP ()
 
int getDefaultConnectBlock (unsigned char *connect_block)
 
int setConnectBlock (const unsigned char *connect_block)
 
int getConnectBlock (unsigned char *connect_block)
 
int write (int org, int dbnr, int start_adr, int length, const unsigned char *buf, int function=WriteByte)
 
int fetch (int org, int dbnr, int start_adr, int length, unsigned char *buf)
 
- Public Member Functions inherited from rlSocket
 rlSocket (const char *adr, int port, int active)
 
 rlSocket (int socket)
 
virtual ~rlSocket ()
 
void setAdr (const char *adr)
 
void setPort (int port)
 
int getPort ()
 
void setActive (int active)
 
int read (void *buf, int len, int timeout=0)
 
int readStr (char *buf, int len, int timeout=0)
 
int readHttpHeader (rlString *header, int timeout=0)
 
int write (const void *buf, int len)
 
int printf (const char *format,...)
 
int connect ()
 
int disconnect ()
 
int select (int timeout=0)
 
int isConnected ()
 
int setIPVersion (int version)
 
int getIPVersion ()
 
int sendProcessViewBrowserButtonEvent (int id)
 
int rlGetsockopt (int level, int optname)
 
int rlSetsockopt (int level, int optname)
 
int readHttpContentLength (int timeout)
 

Private Member Functions

void doConnect ()
 
int read_iso (unsigned char *buf)
 
int write_iso (unsigned char *buf, int len)
 
int getOrg (int org)
 
int write_bit (int &i, int org, int dbnr, int start_adr, int len, const unsigned char *buf)
 
int write_byte (int &i, int org, int dbnr, int start_adr, int length, const unsigned char *buf)
 

Private Attributes

WH wh
 
WA wa
 
FH fh
 
FA fa
 
IH ih
 
int function
 
int rack_slot
 
int plc_type
 
int fetch_write
 
unsigned char pdu [2048]
 
int use_cb
 
unsigned char cb [22]
 

Additional Inherited Members

- Static Public Member Functions inherited from rlSocket
static int rlGetsockopt (int sockfd, int level, int optname, void *optval, int *optlen)
 
static int rlSetsockopt (int sockfd, int level, int optname, const void *optval, int optlen)
 
- Public Attributes inherited from rlSocket
int s
 
unsigned char sockaddr [16+48]
 

Detailed Description

class for communication with Siemens PLC's via TCP
(1) There is the old Fetch/Write protocol from the old S5 PLC (fetch_write=1).
(2) And there is the current Siemens PLC protocol introduced with the S7 series of PLC (fetch_write=0).
According to
http://www.ietf.org/rfc/rfc0905.txt
the client will send a connection request to the PLC after it has establisched a TCP connection().
Here is a example connect_block for a Siemens S7 PLC (CBxx in hex):
CB00= 3, ISO_HEADER_VERSION
CB01= 0, ISO_HEADER_RESERVED
CB02= 0, ISO_HEADER_LENGHT_HIGH
CB03=16, ISO_HEADER_LENGHT_LOW = 22 Byte (hex 16)
CB04=11, Length Indicator Field = 17 dec = 22 byte_total_length - 1 byte_length_indicator - 4 byte_ISO_HEADER
CB05=E0, Connection Request Code (Bits 8-5) 1110=E, Initial Credit Allocation (Bits 4-1) Class 0
CB06= 0, DESTINATION-REF-HIGH
CB07= 0, DESTINATION-REF-LOW
CB08= 0, SOURCE-REF-HIGH
CB09= 1, SOURCE-REF-LOW
CB10= 0, Class and Option
CB11=C1, Identifier: Calling TSAP will follow
CB12= 2, Parameter Length, 2 byte will follow
CB13= 1, Remote TSAP, free to choose on client side       (1=PG,2=OP,3=Step7Basic) suggested
CB14= 0, Remote TSAP, free to choose on client side       (upper_3_bit_is_rack / lower_5_bit_is_slot) suggested
CB15=C2, Identifier: Called TSAP will follow
CB16= 2, Parameter Length, 2 byte will follow
CB17= 1, Local TSAP,  set within Step7 = 1                (1=PG,2=OP,3=Step7Basic)
CB18= 0, Local TSAP,  set within Step7 = 0...connectionN  (upper_3_bit_is_rack / lower_5_bit_is_slot)
CB19=C0, Identifier: Maximum TPDU size will follow
CB20= 1, Parameter Length, 1 byte will follow 
CB21= 9, max 512 octets
For the different PLC types the connect_block looks as follows:
s7_200  = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,'M','W',0xC2,2,'M','W',0xC0,1,9} 
s7_300  = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,  1,0  ,0xC2,2,  1,2  ,0xC0,1,9} on S7_300 slot of cpu is always 2
s7_400  = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,  1,0  ,0xC2,2,  1,3  ,0xC0,1,9} on S7_400 slot of cpu is always 3
s7_1200 = {3,0,0,16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,  1,0  ,0xC2,2,  1,0  ,0xC0,1,9} slot may be 0 || 1 and TSAP 03.01 || 10.00
s7_logo = {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,  2,0  ,0xC2,2,  2,0  ,0xC0,1,9} 
For S7_200 and S7_1200 read: (only symbolic access to DB1) 
http://support.automation.siemens.com/WW/llisapi.dll?func=cslib.csinfo&lang=en&objid=21601611&caller=view
According to the Remote TSAP Siemens makes the following statement:
######################################################################################
Remote TSAP (Remote Transport Service Access Point, entfernter Dienstzugangspunkt)
The representation is the same as with the Local TSAP, 
but the second byte has another meaning:
  • first Byte: contains a device id (allowed 02 or 03) 02 OS (Operating Station Bedienen und Beobachten) 03 other suggested: 02
  • second Byte: contains the adressing within the SIMATIC S7-CPU, divided in: Bit 7 ... 5 Rack (Subsystem) of the S7-CPU Bit 4 ... 0 Slot of the S7-CPU Hint: It is suggested to choose the same settings for Byte 1 in Remote and Local TSAP ######################################################################################
When you use our rlSiemensTCP class you can do it as follows:
unsigned char cb[22];
rlSiemensTCP *plc = new rlSiemensTCP(adr);
plc->getDefaultConnectBlock(cb);
cb[13] = 1; // set 1 Byte of Remote TSAP
cb[14] = 0; // set 2 Byte of Remote TSAP
cb[17] = 1; // set Local TSAP of the PLC to the
cb[18] = 0; // configuration done within Step 7 
plc->setConnectBlock(cb);
Now you can read/write the PLC.
The following matrix shows some combinations:
--------------------------------------------
             | CB13    CB14    CB17   CB18
--------------------------------------------
S7_200       | 'M'     'W'      'M'    'W'
--------------------------------------------
S7_300       |  1       0        1      2
--------------------------------------------
S7_400       |  1       0        1      3
--------------------------------------------
S7_1200      |  1       0        1      0
--------------------------------------------
S7_logo 0BA7 |  2       0        2      0
--------------------------------------------
CB17 = (1=PG,2=OP,3=Step7Basic)
CB18 = (upper_3_bit_is_rack / lower_5_bit_is_slot)
Thus the above would be:
A TSAP within Step 7 of 10.00 results in: cb[17] = PG; cb[18] = 0; // rack=0 slot=0 
A TSAP within Step 7 of 10.01 results in: cb[17] = PG; cb[18] = 1; // rack=0 slot=1
A TSAP within Step 7 of 10.02 results in: cb[17] = PG; cb[18] = 2; // rack=0 slot=2
A TSAP within Step 7 of 10.03 results in: cb[17] = PG; cb[18] = 3; // rack=0 slot=3
You may use rlSiemensTCP with the individual plc_type for conveniance.
But you can set the whole connect_block and use ANY_SIEMENS_COMPATIBLE_PLC.
Please use Wireshark or tcpdump if the settings of the above matrix do not work for you.
Send us your results.
PS: Still wondering about 'M' 'W' on S7-200

Definition at line 130 of file rlsiemenstcp.h.

Member Enumeration Documentation

◆ ORG

Enumerator
ORG_DB 
ORG_M 
ORG_E 
ORG_A 
ORG_PEPA 
ORG_Z 
ORG_T 

Definition at line 133 of file rlsiemenstcp.h.

◆ PLC_TYPE

Enumerator
ANY_SIEMENS_COMPATIBLE_PLC 
S7_200 
S7_300 
S7_400 
S5 
RACK_SLOT 
S7_1200 
LOGO 

Definition at line 143 of file rlsiemenstcp.h.

144  {
146  S7_200 = 1,
147  S7_300 = 2,
148  S7_400 = 3,
149  S5 = 4,
150  RACK_SLOT = 5,
151  S7_1200 = 6, // patch from user slammera from our forum (8 Nov 2012)
152  LOGO = 7 // LOGO! 0BA7, according to jjmg_engenharia from our forum (3 Sep 2013)
153  };

◆ SiemensFunctionCodes

Enumerator
WriteBit 
WriteByte 

Definition at line 154 of file rlsiemenstcp.h.

155  {
156  WriteBit = 1,
157  WriteByte = 2
158  };

Constructor & Destructor Documentation

◆ rlSiemensTCP()

rlSiemensTCP::rlSiemensTCP ( const char *  adr,
int  _plc_type = rlSiemensTCP::ANY_SIEMENS_COMPATIBLE_PLC,
int  _fetch_write = 1,
int  function = -1,
int  rack_slot = -1 
)

Definition at line 31 of file rlsiemenstcp.cpp.

32  :rlSocket(a,ISO_PORT,1)
33 {
34  plc_type = _plc_type;
35  fetch_write = _fetch_write;
36  function = _function;
37  rack_slot = _rack_slot;
38  //doConnect();
39  use_cb = 0;
40  unsigned char connect_block[22];
41  getDefaultConnectBlock(connect_block);
42  memcpy(cb,connect_block,sizeof(cb));
43 }
rlSocket(const char *adr, int port, int active)
Definition: rlsocket.cpp:130
int getDefaultConnectBlock(unsigned char *connect_block)
#define ISO_PORT
unsigned char cb[22]
Definition: rlsiemenstcp.h:252

◆ ~rlSiemensTCP()

rlSiemensTCP::~rlSiemensTCP ( )
virtual

Definition at line 45 of file rlsiemenstcp.cpp.

46 {
48 }
int disconnect()
Definition: rlsocket.cpp:545

Member Function Documentation

◆ doConnect()

void rlSiemensTCP::doConnect ( )
private

Definition at line 71 of file rlsiemenstcp.cpp.

72 {
73  int i,i2,ret,length;
74  static const unsigned char s7_200_connect_block[] =
75  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,'M','W',0xC2,2,'M','W',0xC0,1,9};
76  static const unsigned char s7_300_connect_block[] =
77  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,1 ,2 ,0xC0,1,9};
78  static const unsigned char s7_400_connect_block[] =
79  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,1 ,3 ,0xC0,1,9};
80  static const unsigned char s7_1200_connect_block[] =
81  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,1 ,0 ,0xC0,1,9};
82  static const unsigned char logo_connect_block[] =
83  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00, 0xC0,1,9, 0xC1,2,2,0, 0xC2,2,2,0};
84  //{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,2, 0 ,0xC2,2,2 ,0 ,0xC0,1,9}; // this should be equivalent to the above (see detailed description)
85  static const unsigned char other_connect_block[] =
86  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,0 ,1 ,0xC0,1,9};
87  //######### Description of the individual bytes within the connect_block (connect request) ###
88  //{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,0 ,1 ,0xC0,1,9};
89  // | | | | | |- Identifier: Maximum TPDU size will follow, 1 byte,
90  // | | | | | where 9 means max 512 octets
91  // | | | | |---------------- Identifier: Called TSAP will follow, 2 byte,
92  // | | | | where (1=PG, 2=OP, 3=Step7Basic),
93  // | | | | rack=0 slot=1 (upper_3_bit_is_rack /
94  // | | | | lower_5_bit_is_slot)
95  // | | | |------------------------------- Identifier: Calling TSAP will follow, 2 byte,
96  // | | | where (1=PG, 2=OP) 3=Step7Basic),
97  // | | | rack=0 slot=0 (upper_3_bit_is_rack /
98  // | | | lower_5_bit_is_slot)
99  // | | |------------------------------------------------------------ 0xEO = Connection Request Code,
100  // | | destination ref high/low = 0,0
101  // | | source ref high/low = 0,1
102  // | | Class and Option = 0
103  // | |----------------------------------------------------------------- 0x11 = 17 = Number of bytes that follow
104  // |--------------------------------------------------------------------------- ISO_HEADER: version=3 reserved=0
105  // lenght_high=0 length_low=22 byte
106  //#############################################################################################
107  unsigned char connect_block[22];
108 
109  unsigned char connect_block2[] =
110  {0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0xCC,0xC1,0x00,0x08,0x00,0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x03,0xC0};
111  unsigned char buf[512];
112 
113  if(use_cb)
114  {
115  memcpy(connect_block,cb,sizeof(cb));
116  }
117  else
118  {
119  if (plc_type == S7_200) memcpy(connect_block,s7_200_connect_block,sizeof(connect_block));
120  else if(plc_type == S7_300) memcpy(connect_block,s7_300_connect_block,sizeof(connect_block));
121  else if(plc_type == S7_400) memcpy(connect_block,s7_400_connect_block,sizeof(connect_block));
122  else if(plc_type == S7_1200) memcpy(connect_block,s7_1200_connect_block,sizeof(connect_block));
123  else if(plc_type == LOGO) memcpy(connect_block,logo_connect_block,sizeof(connect_block));
124  else memcpy(connect_block,other_connect_block,sizeof(connect_block));
125 
126  // according to an unproofen theory siemens chooses the TSAP as follows
127  // connect_block[17] = 2; Function (1=PG,2=OP,3=Step7Basic)
128  // connect_block[18] = upper_3_bit_is_rack / lower_5_bit_is_slot
129  // Hint: use tcpdump to figure it out (host = ip_adr of your PLC)
130  // tcpdump -A -i eth0 -t -q -s 0 "host 192.168.1.14 && port 102"
131  if(function != -1) connect_block[17] = function;
132  if(rack_slot != -1) connect_block[18] = rack_slot;
133  }
134 
135  for(i=0; i<3; i++)
136  {
137  if(rlSocket::connect() >= 0)
138  {
139  // exchange TSAP
140  rlDebugPrintf("write connect_block\n");
141  rlSocket::write(connect_block,sizeof(connect_block));
142  ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
143  rlDebugPrintf("read ih ret=%d\n",ret);
144  if(ret <= 0) { rlSocket::disconnect(); continue; }
145  length = ih.length_high*256 + ih.length_low;
146  rlDebugPrintf("read buf length=%d\n",length);
147  ret = rlSocket::read(buf,length-sizeof(ih),TIMEOUT);
148  rlDebugPrintf("read buf ret=%d\n",ret);
149  if(ret <= 0) { rlSocket::disconnect(); continue; }
150  if(length == 22)
151  {
152  for(i2=0; i2<3; i2++)
153  {
154  rlDebugPrintf("write connect_block2\n");
155  rlSocket::write(connect_block2,sizeof(connect_block2));
156  ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
157  rlDebugPrintf("read2 ih ret=%d\n",ret);
158  length = ih.length_high*256 + ih.length_low;
159  rlDebugPrintf("read2 buf length=%d\n",length);
160  ret = rlSocket::read(buf,length-sizeof(ih),TIMEOUT);
161  rlDebugPrintf("read2 buf ret=%d\n",ret);
162  if(ret <= 0) { rlSocket::disconnect(); continue; }
163  if(ret > 0)
164  {
165  rlDebugPrintf("connect success\n");
166  return;
167  }
168  }
170  return;
171  }
172  }
173  else
174  {
175  rlsleep(100);
176  rlDebugPrintf("connect failed\n");
177  }
178  }
179 }
int rlDebugPrintf(const char *format,...)
Definition: rlcutil.cpp:61
int write(const void *buf, int len)
Definition: rlsocket.cpp:292
unsigned char length_low
Definition: rlsiemenstcp.h:180
#define TIMEOUT
int read(void *buf, int len, int timeout=0)
Definition: rlsocket.cpp:191
void rlsleep(long msec)
Definition: rlwthread.cpp:396
int connect()
Definition: rlsocket.cpp:321
int disconnect()
Definition: rlsocket.cpp:545
unsigned char cb[22]
Definition: rlsiemenstcp.h:252
unsigned char length_high
Definition: rlsiemenstcp.h:179

◆ fetch()

int rlSiemensTCP::fetch ( int  org,
int  dbnr,
int  start_adr,
int  length,
unsigned char *  buf 
)

Definition at line 434 of file rlsiemenstcp.cpp.

435 {
436  int i,ret,len_byte,length;
437 
438  if(rlSocket::isConnected() == 0) doConnect();
439  if(rlSocket::isConnected() == 0) return -1;
440 
441  len_byte = len;
442  //if(org == ORG_DB) len_byte *= 2;
443  //if(org == ORG_Z) len_byte *= 2;
444  //if(org == ORG_T) len_byte *= 2;
445 
446  if((plc_type == S5 || plc_type == S7_300 || plc_type == S7_400) && fetch_write == 1)
447  {
448  length = sizeof(ih) + sizeof(fh);
449  ih.version = 3;
450  ih.reserved = 0;
451  ih.length_high = length / 256;
452  ih.length_low = length & 0x0ff;
453  fh.ident[0] = 'S';
454  fh.ident[1] = '5';
455  fh.header_len = 16;
456  fh.ident_op_code = 1;
457  fh.op_code_len = 3;
458  fh.op_code = 5;
459  fh.ident_org_block = 3;
460  fh.len_org_block = 8;
461  fh.org_block = (unsigned char) org;
462  fh.dbnr = (unsigned char) dbnr;
463  fh.start_adr[0] = (unsigned char) start_adr / 256;
464  fh.start_adr[1] = (unsigned char) start_adr & 0x0ff;;
465  fh.len[0] = (unsigned char) len / 256;
466  fh.len[1] = (unsigned char) len & 0x0ff;;
467  fh.spare1 = 0x0ff;
468  fh.spare1_len = 2;
469  unsigned char total_buf[sizeof(ih)+sizeof(fh)];
470  memcpy(total_buf, &ih, sizeof(ih));
471  memcpy(total_buf+sizeof(ih), &fh, sizeof(fh));
472  ret = rlSocket::write(total_buf, sizeof(ih)+sizeof(fh));
473  rlDebugPrintf("fetch write ih ret=%d\n",ret);
474  if(ret < 0) return ret;
475  /*
476  ret = rlSocket::write(&ih,sizeof(ih));
477  rlDebugPrintf("fetch write ih ret=%d\n",ret);
478  if(ret < 0) return ret;
479  ret = rlSocket::write(&fh,sizeof(fh));
480  rlDebugPrintf("fetch write fh ret=%d\n",ret);
481  if(ret < 0) return ret;
482  */
483  ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
484  rlDebugPrintf("fetch read ih ret=%d\n",ret);
485  if(ret <= 0) return ret;
486  ret = rlSocket::read(&fa,sizeof(fa),TIMEOUT);
487  rlDebugPrintf("fetch read fa ret=%d\n",ret);
488  if(ret <= 0) return ret;
489  if(fa.error_block != 0) return -1;
490  ret = rlSocket::read(buf,len_byte,TIMEOUT);
491  rlDebugPrintf("fetch read buf ret=%d\n",ret);
492  if(ret <= 0) return ret;
493  }
494  else
495  {
496  rlDebugPrintf("fetch:starting org=%d dbnr=%d start_adr=%d len=%d\n", org, dbnr, start_adr, len);
497  i = 0;
498  pdu[i++] = 0x02; // [0]
499  pdu[i++] = 0xF0; // [0]
500  pdu[i++] = 0x80; // [0]
501  pdu[i++] = 0x32; // [0]
502  pdu[i++] = 0x01; // [0]
503  pdu[i++] = 0x00; // [0]
504  pdu[i++] = 0x00; // [0]
505  pdu[i++] = 0x00; // [0]
506  pdu[i++] = 0x00; // [0]
507  pdu[i++] = 0x00; // [0]
508  pdu[i++] = 0x0E; // [0]
509  pdu[i++] = 0x00; // [0]
510  pdu[i++] = 0x00; // [0]
511  pdu[i++] = 0x04; // [0] read
512  pdu[i++] = 0x01; // [1]
513  pdu[i++] = 0x12; // [2]
514  pdu[i++] = 0x0A; // [3]
515  pdu[i++] = 0x10; // [4]
516  pdu[i++] = 0x02; // [5]
517  pdu[i++] = len_byte / 256; //0x00; // [6] len/bytes
518  pdu[i++] = len_byte & 0x0ff; //0x40; // [7] len/bytes
519  pdu[i++] = dbnr / 256; //0x00; // [8] dbnum
520  pdu[i++] = dbnr & 0x0ff; //0x01; // [9] dbnum
521  pdu[i++] = getOrg(org); //10
522  pdu[i] = ((start_adr*8)/0x010000) & 0x0ff; //0x00; // [11] start adr/bits
523  if (plc_type == S7_200) pdu[i] = start_adr / 0x10000;
524  i++;
525  pdu[i++] = ((start_adr*8)/0x0100) & 0x0ff; //0x00; // [12] start adr/bits
526  pdu[i++] = (start_adr*8) & 0x0ff; //0x00; // [13] start adr/bits
527  ret = write_iso(pdu,i);
528  if(ret < 0)
529  {
530  rlDebugPrintf("fetch:write_iso error ret==%d -> return -1\n", ret);
531  return ret;
532  }
533  ret = read_iso(pdu);
534  if(ret < 0)
535  {
536  rlDebugPrintf("fetch:read_iso error ret==%d -> return -1\n", ret);
537  return ret;
538  }
539  if(pdu[15] != 0x04)
540  {
541  rlDebugPrintf("fetch:pdu[15]=%d is not equal 0x04-> return -1\n", pdu[15]);
542  return -1;
543  }
544  if(pdu[16] != 0x01)
545  {
546  rlDebugPrintf("fetch:pdu[16]=%d is not equal 0x04-> return -1\n", pdu[16]);
547  return -1;
548  }
549  i = 21;
550  if(ret < i+len_byte) return -1;
551  for(int ibuf = 0; ibuf < len_byte; ibuf++)
552  {
553  buf[ibuf] = pdu[i++];
554  }
555  }
556  rlDebugPrintf("fetch:success len_byte=%d\n", len_byte);
557 
558  return len_byte;
559 }
int rlDebugPrintf(const char *format,...)
Definition: rlcutil.cpp:61
unsigned char len_org_block
Definition: rlsiemenstcp.h:220
int write_iso(unsigned char *buf, int len)
int write(const void *buf, int len)
Definition: rlsocket.cpp:292
unsigned char version
Definition: rlsiemenstcp.h:177
unsigned char ident_org_block
Definition: rlsiemenstcp.h:219
unsigned char error_block
Definition: rlsiemenstcp.h:237
unsigned char length_low
Definition: rlsiemenstcp.h:180
unsigned char ident[2]
Definition: rlsiemenstcp.h:214
#define TIMEOUT
unsigned char dbnr
Definition: rlsiemenstcp.h:222
unsigned char org_block
Definition: rlsiemenstcp.h:221
int read_iso(unsigned char *buf)
unsigned char pdu[2048]
Definition: rlsiemenstcp.h:250
unsigned char len[2]
Definition: rlsiemenstcp.h:224
int read(void *buf, int len, int timeout=0)
Definition: rlsocket.cpp:191
int getOrg(int org)
unsigned char op_code
Definition: rlsiemenstcp.h:218
unsigned char spare1_len
Definition: rlsiemenstcp.h:226
void doConnect()
unsigned char ident_op_code
Definition: rlsiemenstcp.h:216
unsigned char reserved
Definition: rlsiemenstcp.h:178
unsigned char start_adr[2]
Definition: rlsiemenstcp.h:223
int isConnected()
Definition: rlsocket.cpp:559
unsigned char spare1
Definition: rlsiemenstcp.h:225
unsigned char op_code_len
Definition: rlsiemenstcp.h:217
unsigned char header_len
Definition: rlsiemenstcp.h:215
unsigned char length_high
Definition: rlsiemenstcp.h:179

◆ getConnectBlock()

int rlSiemensTCP::getConnectBlock ( unsigned char *  connect_block)

Definition at line 65 of file rlsiemenstcp.cpp.

66 {
67  memcpy(connect_block,cb,sizeof(cb));
68  return 0;
69 }
unsigned char cb[22]
Definition: rlsiemenstcp.h:252

◆ getDefaultConnectBlock()

int rlSiemensTCP::getDefaultConnectBlock ( unsigned char *  connect_block)
 

Definition at line 50 of file rlsiemenstcp.cpp.

51 {
52  static const unsigned char default_connect_block[] =
53  {3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,0 ,1 ,0xC0,1,9};
54  memcpy(connect_block,default_connect_block,sizeof(default_connect_block));
55  return 22;
56 }

◆ getOrg()

int rlSiemensTCP::getOrg ( int  org)
private

Definition at line 181 of file rlsiemenstcp.cpp.

182 {
183  int ret;
184  switch(org)
185  {
186  /* before suggestions from sps-forum.de
187  case ORG_DB: ret = 0x84; break; //[10] Datenbaustein
188  case ORG_M: ret = 0x83; break; //[10] Merker
189  case ORG_E: ret = 0x81; break; //[10] Eingang
190  case ORG_A: ret = 0x82; break; //[10] Ausgang
191  case ORG_PEPA: ret = 0x80; break; //[10] Peripheral Area R/W [tested by VSA]
192  case ORG_Z: ret = 0x84; break; //[10] not tested
193  case ORG_T: ret = 29; break; //[10] Timer
194  default: return 0x83; break;
195  */
196  case ORG_DB: ret = 0x84; break; //[10] Datenbaustein
197  case ORG_M: ret = 0x83; break; //[10] Merker
198  case ORG_E: ret = 0x81; break; //[10] Eingang
199  case ORG_A: ret = 0x82; break; //[10] Ausgang
200  case ORG_PEPA: ret = 0x80; break; //[10] Peripheral Area R/W [tested by VSA]
201  case ORG_Z: ret = 28; //[10] Zaehler // according sps-forum.de ---
202  if(plc_type==S7_200) ret = 30; // according sps-forum.de ...
203  break;
204  case ORG_T: ret = 29; //[10] Timer
205  if(plc_type==S7_200) ret = 31; // according sps-forum.de ...
206  break; // J. Kühner and R. Hönle
207  // Attention: The encoding of Zaehler and Timer will be different on S7_200 than to other plc models
208  default: return 0x83; break;
209  }
210  return ret;
211 }

◆ read_iso()

int rlSiemensTCP::read_iso ( unsigned char *  buf)
private

Definition at line 561 of file rlsiemenstcp.cpp.

562 {
563  int i,ret,len;
564 
565  ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
566  if(ret < 0)
567  {
568  rlDebugPrintf("read_iso:failure to read iso header ret=%d -> disconnecting\n", ret);
570  return ret;
571  }
572  if(ih.version != 3)
573  {
574  rlDebugPrintf("read_iso:header vesion mismatch version==%d -> disconnecting\n", ret);
576  return -1;
577  }
578  len = ih.length_high*256 + ih.length_low - 4;
579  if(len <= 0)
580  {
581  rlDebugPrintf("read_iso:len==%d from iso header is negative -> disconnecting\n", len);
583  return -1;
584  }
585  if(len > (int) sizeof(pdu))
586  {
587  rlDebugPrintf("read_iso:len==%d from iso header is larger than max PDU size -> disconnecting\n", len);
589  return -1;
590  }
591  ret = rlSocket::read(buf,len,TIMEOUT);
592  if(ret < 0)
593  {
594  rlDebugPrintf("read_iso:read buf got timeout -> disconnecting\n");
596  return ret;
597  }
598  if(rlDebugPrintfState != 0)
599  {
600  ::printf("read_iso() len=%d\n", len);
601  for(i=0; i<len; i++) ::printf("%02x,",buf[i]);
602  ::printf("\n");
603  }
604  return len;
605 }
int rlDebugPrintf(const char *format,...)
Definition: rlcutil.cpp:61
unsigned char version
Definition: rlsiemenstcp.h:177
unsigned char length_low
Definition: rlsiemenstcp.h:180
#define TIMEOUT
unsigned char pdu[2048]
Definition: rlsiemenstcp.h:250
int read(void *buf, int len, int timeout=0)
Definition: rlsocket.cpp:191
int rlDebugPrintfState
Definition: rlcutil.cpp:52
int disconnect()
Definition: rlsocket.cpp:545
unsigned char length_high
Definition: rlsiemenstcp.h:179
int printf(const char *format,...)
Definition: rlsocket.cpp:586

◆ setConnectBlock()

int rlSiemensTCP::setConnectBlock ( const unsigned char *  connect_block)

Definition at line 58 of file rlsiemenstcp.cpp.

59 {
60  memcpy(cb,connect_block,sizeof(cb));
61  use_cb = 1;
62  return 0;
63 }
unsigned char cb[22]
Definition: rlsiemenstcp.h:252

◆ write()

int rlSiemensTCP::write ( int  org,
int  dbnr,
int  start_adr,
int  length,
const unsigned char *  buf,
int  function = WriteByte 
)

Definition at line 212 of file rlsiemenstcp.cpp.

213 {
214  int i,ibuf,ret,len_byte,length;
215  if(rlSocket::isConnected() == 0) doConnect();
216  if(rlSocket::isConnected() == 0) return -1;
217 
218  len_byte = len;
219  if(len_byte > (int) sizeof(pdu)) return -1;
220  //if(org == ORG_DB) len_byte *= 2;
221  //if(org == ORG_Z) len_byte *= 2;
222  //if(org == ORG_T) len_byte *= 2;
223 
224  if((plc_type == S5 || plc_type == S7_300 || plc_type == S7_400) && fetch_write == 1)
225  {
226  rlDebugPrintf("using fetch_write\n");
227  length = sizeof(ih) + sizeof(wh) + len_byte;
228  unsigned char total_buf[sizeof(ih) + sizeof(wh) + sizeof(pdu)];
229  ih.version = 3;
230  ih.reserved = 0;
231  ih.length_high = length / 256;
232  ih.length_low = length & 0x0ff;
233  wh.ident[0] = 'S';
234  wh.ident[1] = '5';
235  wh.header_len = 16;
236  wh.ident_op_code = 1;
237  wh.op_code_len = 3;
238  wh.op_code = 3;
239  wh.ident_org_block = 3;
240  wh.len_org_block = 8;
241  wh.org_block = (unsigned char) org;
242  wh.dbnr = (unsigned char) dbnr;
243  wh.start_adr[0] = (unsigned char) start_adr / 256;
244  wh.start_adr[1] = (unsigned char) start_adr & 0x0ff;;
245  wh.len[0] = (unsigned char) len / 256;
246  wh.len[1] = (unsigned char) len & 0x0ff;;
247  wh.spare1 = 0x0ff;
248  wh.spare1_len = 2;
249  memcpy(total_buf, &ih, sizeof(ih));
250  memcpy(total_buf+sizeof(ih), &wh, sizeof(wh));
251  memcpy(total_buf+sizeof(ih)+sizeof(wh), buf, len_byte);
252  ret = rlSocket::write(total_buf, sizeof(ih)+sizeof(wh)+len_byte);
253  rlDebugPrintf("write total_buf ret=%d\n",ret);
254  if(ret < 0) return ret;
255  /*
256  ret = rlSocket::write(&ih,sizeof(ih));
257  rlDebugPrintf("write ih ret=%d\n",ret);
258  if(ret < 0) return ret;
259  ret = rlSocket::write(&wh,sizeof(wh));
260  rlDebugPrintf("write wh ret=%d\n",ret);
261  if(ret < 0) return ret;
262  ret = rlSocket::write(buf,len_byte);
263  rlDebugPrintf("write buf ret=%d\n",ret);
264  if(ret < 0) return ret;
265  */
266  ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
267  rlDebugPrintf("read ih ret=%d\n",ret);
268  if(ret <= 0) return ret;
269  ret = rlSocket::read(&wa,sizeof(wa),TIMEOUT);
270  rlDebugPrintf("read wa ret=%d\n",ret);
271  if(ret <= 0) return ret;
272  if(wa.error_block != 0) return -1;
273  }
274  else
275  {
276  rlDebugPrintf("not using fetch_write\n");
277  i = 0;
278  pdu[i++] = 0x02;
279  pdu[i++] = 0xF0;
280  pdu[i++] = 0x80;
281  pdu[i++] = 0x32;
282  pdu[i++] = 0x01;
283  pdu[i++] = 0x00;
284  pdu[i++] = 0x00;
285  pdu[i++] = 0x00;
286  pdu[i++] = 0x00;
287  pdu[i++] = 0x00;
288  // The S7 update by Aljosa Merljak was tested on S7_200 only
289  // You could set your plc_type to S7_200 also, even if you have S7_300 || S7_400
290  // But only the else part has been tested with S7_300 and S7_400 up to now
291  //if(plc_type == S7_200)
292  // Hi Ken, currently only S7_200 was tested with this. But try if this also works with S7_400
293  if(plc_type >0) // works for all known plc_type == S7_200 || plc_type == S7_300 || plc_type == S7_400)
294  {
295  ret = 0;
296  switch(function)
297  {
298  case WriteBit: ret = write_bit (i, org, dbnr, start_adr, len, buf); break;
299  case WriteByte: ret = write_byte (i, org, dbnr, start_adr, len, buf); break;
300  }
301  if(ret < 0) return ret;
302  }
303  else // will only work for WriteByte with len_byte = 4
304  {
305  pdu[i++] = 0x0E;
306  pdu[i++] = 0x00;
307  pdu[i++] = 0x08;
308  pdu[i++] = 0x05; //0 write
309  pdu[i++] = 0x01; //1
310  pdu[i++] = 0x12; //2
311  pdu[i++] = 0x0A; //3
312  pdu[i++] = 0x10; //4
313  pdu[i++] = 0x02; //5
314  pdu[i++] = len_byte / 256; //6 0x00;
315  pdu[i++] = len_byte & 0x0ff; //7 0x04;
316  pdu[i++] = dbnr / 256; //8 0x00;
317  pdu[i++] = dbnr & 0x0ff; //9 0x00;
318  pdu[i++] = getOrg(org); //10
319  pdu[i++] = ((start_adr*8)/0x010000) & 0x0ff; //0x00; // [11] start adr/bits
320  pdu[i++] = ((start_adr*8)/0x0100) & 0x0ff; //0x00; // [12] start adr/bits
321  pdu[i++] = (start_adr*8) & 0x0ff; //0x00; // [13] start adr/bits
322  pdu[i++] = 0x00;
323  pdu[i++] = 0x04;
324  pdu[i++] = 0x00;
325  pdu[i++] = 0x20;
326  for(ibuf=0; ibuf<len_byte; ibuf++)
327  {
328  pdu[i++] = buf[ibuf];
329  if(i > (int) sizeof(pdu)) return -1;
330  }
331  }
332  ret = write_iso(pdu,i);
333  if(ret < 0) return ret;
334  ret = read_iso(pdu);
335  if(ret < 0) return ret;
336  if(pdu[15] != 0x05) return -1;
337  if(pdu[16] != 0x01) return -1;
338 
339  // CODE from Víctor Centelles
340  if(pdu[17] != 0xff)
341  {
342  if(pdu[17] == 0x0a){
343  fprintf( stderr, " > Error: Trying to access a DB that does not exist\n");
344  fprintf( stderr, "          Please, check that DB is set.   (error code: 10 (0x0a))\n");
345  return -(pdu[17]);
346  }
347  else if(pdu[17] == 0x05){
348  fprintf(stderr, " > Error: Trying to access an address that does not exist.\n");
349  fprintf(stderr, "          Please, check the address range. (error code: 5 (0x05))\n");
350  return -(pdu[17]);
351  }
352  else if(pdu[17] == 0x07){
353  fprintf(stderr, " > Error: the write data size doesn't fit item size\n"); // NO TESTED!!!
354  fprintf(stderr, "          Please, check the data size.     (error code: 7 (0x07))\n");
355  return -(pdu[17]);
356  }
357  else{
358  fprintf(stderr, " > Error: unknown error  (código %x!=0xff)\n", pdu[17]);
359  return -(pdu[17]);
360  }
361  }
362  }
363 
364  return len_byte;
365 }
int rlDebugPrintf(const char *format,...)
Definition: rlcutil.cpp:61
unsigned char spare1_len
Definition: rlsiemenstcp.h:196
unsigned char error_block
Definition: rlsiemenstcp.h:207
int write_iso(unsigned char *buf, int len)
unsigned char spare1
Definition: rlsiemenstcp.h:195
int write(const void *buf, int len)
Definition: rlsocket.cpp:292
unsigned char version
Definition: rlsiemenstcp.h:177
unsigned char ident[2]
Definition: rlsiemenstcp.h:184
unsigned char org_block
Definition: rlsiemenstcp.h:191
unsigned char length_low
Definition: rlsiemenstcp.h:180
unsigned char op_code
Definition: rlsiemenstcp.h:188
unsigned char start_adr[2]
Definition: rlsiemenstcp.h:193
unsigned char op_code_len
Definition: rlsiemenstcp.h:187
unsigned char len_org_block
Definition: rlsiemenstcp.h:190
unsigned char header_len
Definition: rlsiemenstcp.h:185
#define TIMEOUT
int read_iso(unsigned char *buf)
unsigned char pdu[2048]
Definition: rlsiemenstcp.h:250
unsigned char dbnr
Definition: rlsiemenstcp.h:192
int read(void *buf, int len, int timeout=0)
Definition: rlsocket.cpp:191
unsigned char len[2]
Definition: rlsiemenstcp.h:194
int getOrg(int org)
int write_bit(int &i, int org, int dbnr, int start_adr, int len, const unsigned char *buf)
void doConnect()
unsigned char ident_op_code
Definition: rlsiemenstcp.h:186
unsigned char reserved
Definition: rlsiemenstcp.h:178
int write_byte(int &i, int org, int dbnr, int start_adr, int length, const unsigned char *buf)
int isConnected()
Definition: rlsocket.cpp:559
unsigned char length_high
Definition: rlsiemenstcp.h:179
unsigned char ident_org_block
Definition: rlsiemenstcp.h:189

◆ write_bit()

int rlSiemensTCP::write_bit ( int &  i,
int  org,
int  dbnr,
int  start_adr,
int  len,
const unsigned char *  buf 
)
private

Definition at line 367 of file rlsiemenstcp.cpp.

368 {
369  int j;
370  pdu[i++] = 14 + 12 * (len - 1);
371  pdu[i++] = 0x00;
372  pdu[i++] = 6 * len - 1;
373  pdu[i++] = 0x05;
374  pdu[i++] = len;
375  for(j=0; j<len; j++)
376  {
377  pdu[i++] = 0x12;
378  pdu[i++] = 0x0a;
379  pdu[i++] = 0x10;
380  pdu[i++] = 0x01;
381  pdu[i++] = len / 256; //6 0x00;
382  pdu[i++] = 0x01; //7 number of bytes in group
383  pdu[i++] = dbnr / 256; //8 0x00;
384  pdu[i++] = dbnr & 0x0ff; //9 0x00;
385  pdu[i++] = getOrg(org); //10
386  pdu[i++] = ((start_adr / 8)/0x010000) & 0x0ff;
387  pdu[i++] = (start_adr / 0x0100) & 0x0ff; //0x00; // [12] start adr/bits
388  pdu[i++] = (start_adr + j) & 0x0ff; //0x00; // [13] start adr/bits
389  }
390  for(j=0; j<len; j++)
391  {
392  pdu[i++] = 0x00;
393  pdu[i++] = 0x03;
394  pdu[i++] = 0x00;
395  pdu[i++] = 0x01;
396  pdu[i++] = (buf[j]>0) ? 0x01 : 0x00;
397  if(j < len - 1 ) pdu[i++] = 0x00;
398  if(i > (int) sizeof(pdu)) return -1;
399  }
400  return i;
401 }
unsigned char pdu[2048]
Definition: rlsiemenstcp.h:250
int getOrg(int org)

◆ write_byte()

int rlSiemensTCP::write_byte ( int &  i,
int  org,
int  dbnr,
int  start_adr,
int  length,
const unsigned char *  buf 
)
private

Definition at line 403 of file rlsiemenstcp.cpp.

404 {
405  pdu[i++] = 0x0e;
406  pdu[i++] = 0x00;
407  pdu[i++] = 5 + len - 1;
408  pdu[i++] = 0x05;
409  pdu[i++] = 0x01;
410  pdu[i++] = 0x12;
411  pdu[i++] = 0x0a;
412  pdu[i++] = 0x10;
413  pdu[i++] = 0x02;
414  pdu[i++] = len / 256; //6 0x00;
415  pdu[i++] = len & 0x0ff; //7 number of bytes
416  pdu[i++] = dbnr / 256; //8 0x00;
417  pdu[i++] = dbnr & 0x0ff; //9 0x00;
418  pdu[i++] = getOrg(org); //10
419  pdu[i++] = start_adr /0x10000 & 0x0ff;
420  pdu[i++] = ((start_adr*8)/0x0100) & 0x0ff; //0x00; // [12] start adr/bits
421  pdu[i++] = (start_adr*8) & 0x0ff; //0x00; // [13] start adr/bits
422  pdu[i++] = 0x00;
423  pdu[i++] = 0x04;
424  pdu[i++] = (len * 8) / 256;
425  pdu[i++] = (len * 8) & 0xff;
426  for(int ibuf=0; ibuf<len; ibuf++)
427  {
428  pdu[i++] = buf[ibuf];
429  if(i > (int) sizeof(pdu)) return -1;
430  }
431  return i;
432 }
unsigned char pdu[2048]
Definition: rlsiemenstcp.h:250
int getOrg(int org)

◆ write_iso()

int rlSiemensTCP::write_iso ( unsigned char *  buf,
int  len 
)
private

Definition at line 607 of file rlsiemenstcp.cpp.

608 {
609  int i,ret;
610 
611  if(len > (int) sizeof(pdu)) return -1;
612  if(rlSocket::isConnected() == 0) doConnect();
613  if(rlSocket::isConnected() == 0) return -1;
614 
615  // speedup siemens communication as suggested by Vincent Segui Pascual
616  // do only 1 write
617  unsigned char total_buf[sizeof(ih)+sizeof(pdu)];
618  ih.version = 3;
619  ih.reserved = 0;
620  ih.length_high = (len+4) / 256;
621  ih.length_low = (len+4) & 0x0ff;
622  memcpy(total_buf, &ih, sizeof(ih));
623  memcpy(total_buf + sizeof(ih), buf, sizeof(ih)+len);
624  ret = rlSocket::write(total_buf, sizeof(ih)+len);
625  if(ret < 0)
626  {
627  rlDebugPrintf("write_iso:failure to write buf -> disconnecting\n");
629  return ret;
630  }
631 /*
632  ih.version = 3;
633  ih.reserved = 0;
634  ih.length_high = (len+4) / 256;
635  ih.length_low = (len+4) & 0x0ff;
636  ret = rlSocket::write(&ih,sizeof(ih));
637  if(ret < 0)
638  {
639  rlDebugPrintf("write_iso:failure to write iso header -> disconnecting\n");
640  rlSocket::disconnect();
641  return ret;
642  }
643  ret = rlSocket::write(buf,len);
644  if(ret < 0)
645  {
646  rlDebugPrintf("write_iso:failure to write buf -> disconnecting\n");
647  rlSocket::disconnect();
648  return ret;
649  }
650 */
651  if(rlDebugPrintfState != 0)
652  {
653  ::printf("write_iso() len=%d\n", len);
654  for(i=0; i<len; i++) ::printf("%02x,",buf[i]);
655  ::printf("\n");
656  }
657  return len;
658 }
int rlDebugPrintf(const char *format,...)
Definition: rlcutil.cpp:61
int write(const void *buf, int len)
Definition: rlsocket.cpp:292
unsigned char version
Definition: rlsiemenstcp.h:177
unsigned char length_low
Definition: rlsiemenstcp.h:180
unsigned char pdu[2048]
Definition: rlsiemenstcp.h:250
void doConnect()
unsigned char reserved
Definition: rlsiemenstcp.h:178
int rlDebugPrintfState
Definition: rlcutil.cpp:52
int disconnect()
Definition: rlsocket.cpp:545
int isConnected()
Definition: rlsocket.cpp:559
unsigned char length_high
Definition: rlsiemenstcp.h:179
int printf(const char *format,...)
Definition: rlsocket.cpp:586

Member Data Documentation

◆ cb

unsigned char rlSiemensTCP::cb[22]
private

Definition at line 252 of file rlsiemenstcp.h.

◆ fa

FA rlSiemensTCP::fa
private

Definition at line 245 of file rlsiemenstcp.h.

◆ fetch_write

int rlSiemensTCP::fetch_write
private

Definition at line 249 of file rlsiemenstcp.h.

◆ fh

FH rlSiemensTCP::fh
private

Definition at line 244 of file rlsiemenstcp.h.

◆ function

int rlSiemensTCP::function
private

Definition at line 247 of file rlsiemenstcp.h.

◆ ih

IH rlSiemensTCP::ih
private

Definition at line 246 of file rlsiemenstcp.h.

◆ pdu

unsigned char rlSiemensTCP::pdu[2048]
private

Definition at line 250 of file rlsiemenstcp.h.

◆ plc_type

int rlSiemensTCP::plc_type
private

Definition at line 248 of file rlsiemenstcp.h.

◆ rack_slot

int rlSiemensTCP::rack_slot
private

Definition at line 247 of file rlsiemenstcp.h.

◆ use_cb

int rlSiemensTCP::use_cb
private

Definition at line 251 of file rlsiemenstcp.h.

◆ wa

WA rlSiemensTCP::wa
private

Definition at line 243 of file rlsiemenstcp.h.

◆ wh

WH rlSiemensTCP::wh
private

Definition at line 242 of file rlsiemenstcp.h.


The documentation for this class was generated from the following files: