rllib  1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
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 = 0, S7_200 = 1, S7_300 = 2, S7_400 = 3,
  S5 = 4, RACK_SLOT = 5, S7_1200 = 6
}
 
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 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)
 

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
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[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
--------------------------------------
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 126 of file rlsiemenstcp.h.

Member Enumeration Documentation

Enumerator:
ORG_DB 
ORG_M 
ORG_E 
ORG_A 
ORG_PEPA 
ORG_Z 
ORG_T 

Definition at line 129 of file rlsiemenstcp.h.

{
ORG_DB = 1,
ORG_M = 2,
ORG_E = 3,
ORG_A = 4,
ORG_PEPA = 5,
ORG_Z = 6,
ORG_T = 7
};
Enumerator:
ANY_SIEMENS_COMPATIBLE_PLC 
S7_200 
S7_300 
S7_400 
S5 
RACK_SLOT 
S7_1200 

Definition at line 139 of file rlsiemenstcp.h.

{
S7_200 = 1,
S7_300 = 2,
S7_400 = 3,
S5 = 4,
RACK_SLOT = 5,
S7_1200 = 6 // patch from user slammera from our forum (8 Nov 2012)
};
Enumerator:
WriteBit 
WriteByte 

Definition at line 149 of file rlsiemenstcp.h.

{
WriteBit = 1,
};

Constructor & Destructor Documentation

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.

{
plc_type = _plc_type;
fetch_write = _fetch_write;
function = _function;
rack_slot = _rack_slot;
//doConnect();
use_cb = 0;
unsigned char connect_block[22];
getDefaultConnectBlock(connect_block);
memcpy(cb,connect_block,sizeof(cb));
}
rlSiemensTCP::~rlSiemensTCP ( )
virtual

Definition at line 45 of file rlsiemenstcp.cpp.

Member Function Documentation

void rlSiemensTCP::doConnect ( )
private

Definition at line 71 of file rlsiemenstcp.cpp.

{
int i,i2,ret,length;
static const unsigned char s7_200_connect_block[] =
{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,'M','W',0xC2,2,'M','W',0xC0,1,9};
static const unsigned char s7_300_connect_block[] =
{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,1 ,2 ,0xC0,1,9};
static const unsigned char s7_400_connect_block[] =
{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,1 ,3 ,0xC0,1,9};
static const unsigned char s7_1200_connect_block[] =
{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,1 ,0 ,0xC0,1,9};
static const unsigned char other_connect_block[] =
{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,0 ,1 ,0xC0,1,9};
unsigned char connect_block[22];
unsigned char connect_block2[] =
{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};
unsigned char buf[512];
if(use_cb)
{
memcpy(connect_block,cb,sizeof(cb));
}
else
{
if (plc_type == S7_200) memcpy(connect_block,s7_200_connect_block,sizeof(connect_block));
else if(plc_type == S7_300) memcpy(connect_block,s7_300_connect_block,sizeof(connect_block));
else if(plc_type == S7_400) memcpy(connect_block,s7_400_connect_block,sizeof(connect_block));
else if(plc_type == S7_1200) memcpy(connect_block,s7_1200_connect_block,sizeof(connect_block));
else memcpy(connect_block,other_connect_block,sizeof(connect_block));
// according to an unproofen theory siemens chooses the TSAP as follows
// connect_block[17] = 2; Function (1=PG,2=OP,3=Step7Basic)
// connect_block[18] = upper_3_bit_is_rack / lower_5_bit_is_slot
// Hint: use tcpdump to figure it out (host = ip_adr of your PLC)
// tcpdump -A -i eth0 -t -q -s 0 "host 192.168.1.14 && port 102"
if(function != -1) connect_block[17] = function;
if(rack_slot != -1) connect_block[18] = rack_slot;
}
for(i=0; i<3; i++)
{
if(rlSocket::connect() >= 0)
{
// exchange TSAP
rlDebugPrintf("write connect_block\n");
rlSocket::write(connect_block,sizeof(connect_block));
ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
rlDebugPrintf("read ih ret=%d\n",ret);
if(ret <= 0) { rlSocket::disconnect(); continue; }
length = ih.length_high*256 + ih.length_low;
rlDebugPrintf("read buf length=%d\n",length);
ret = rlSocket::read(buf,length-sizeof(ih),TIMEOUT);
rlDebugPrintf("read buf ret=%d\n",ret);
if(ret <= 0) { rlSocket::disconnect(); continue; }
if(length == 22)
{
for(i2=0; i2<3; i2++)
{
rlDebugPrintf("write connect_block2\n");
rlSocket::write(connect_block2,sizeof(connect_block2));
ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
rlDebugPrintf("read2 ih ret=%d\n",ret);
length = ih.length_high*256 + ih.length_low;
rlDebugPrintf("read2 buf length=%d\n",length);
ret = rlSocket::read(buf,length-sizeof(ih),TIMEOUT);
rlDebugPrintf("read2 buf ret=%d\n",ret);
if(ret <= 0) { rlSocket::disconnect(); continue; }
if(ret > 0)
{
rlDebugPrintf("connect success\n");
return;
}
}
return;
}
}
else
{
rlsleep(100);
rlDebugPrintf("connect failed\n");
}
}
}
int rlSiemensTCP::fetch ( int  org,
int  dbnr,
int  start_adr,
int  length,
unsigned char *  buf 
)

Definition at line 396 of file rlsiemenstcp.cpp.

{
int i,ret,len_byte,length;
if(rlSocket::isConnected() == 0) return -1;
len_byte = len;
//if(org == ORG_DB) len_byte *= 2;
//if(org == ORG_Z) len_byte *= 2;
//if(org == ORG_T) len_byte *= 2;
if((plc_type == S5 || plc_type == S7_300 || plc_type == S7_400) && fetch_write == 1)
{
length = sizeof(ih) + sizeof(fh);
ih.version = 3;
ih.reserved = 0;
ih.length_high = length / 256;
ih.length_low = length & 0x0ff;
fh.ident[0] = 'S';
fh.ident[1] = '5';
fh.header_len = 16;
fh.op_code = 5;
fh.org_block = (unsigned char) org;
fh.dbnr = (unsigned char) dbnr;
fh.start_adr[0] = (unsigned char) start_adr / 256;
fh.start_adr[1] = (unsigned char) start_adr & 0x0ff;;
fh.len[0] = (unsigned char) len / 256;
fh.len[1] = (unsigned char) len & 0x0ff;;
fh.spare1 = 0x0ff;
unsigned char total_buf[sizeof(ih)+sizeof(fh)];
memcpy(total_buf, &ih, sizeof(ih));
memcpy(total_buf+sizeof(ih), &fh, sizeof(fh));
ret = rlSocket::write(total_buf, sizeof(ih)+sizeof(fh));
rlDebugPrintf("fetch write ih ret=%d\n",ret);
if(ret < 0) return ret;
/*
ret = rlSocket::write(&ih,sizeof(ih));
rlDebugPrintf("fetch write ih ret=%d\n",ret);
if(ret < 0) return ret;
ret = rlSocket::write(&fh,sizeof(fh));
rlDebugPrintf("fetch write fh ret=%d\n",ret);
if(ret < 0) return ret;
*/
ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
rlDebugPrintf("fetch read ih ret=%d\n",ret);
if(ret <= 0) return ret;
ret = rlSocket::read(&fa,sizeof(fa),TIMEOUT);
rlDebugPrintf("fetch read fa ret=%d\n",ret);
if(ret <= 0) return ret;
if(fa.error_block != 0) return -1;
ret = rlSocket::read(buf,len_byte,TIMEOUT);
rlDebugPrintf("fetch read buf ret=%d\n",ret);
if(ret <= 0) return ret;
}
else
{
rlDebugPrintf("fetch:starting org=%d dbnr=%d start_adr=%d len=%d\n", org, dbnr, start_adr, len);
i = 0;
pdu[i++] = 0x02; // [0]
pdu[i++] = 0xF0; // [0]
pdu[i++] = 0x80; // [0]
pdu[i++] = 0x32; // [0]
pdu[i++] = 0x01; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x0E; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x00; // [0]
pdu[i++] = 0x04; // [0] read
pdu[i++] = 0x01; // [1]
pdu[i++] = 0x12; // [2]
pdu[i++] = 0x0A; // [3]
pdu[i++] = 0x10; // [4]
pdu[i++] = 0x02; // [5]
pdu[i++] = len_byte / 256; //0x00; // [6] len/bytes
pdu[i++] = len_byte & 0x0ff; //0x40; // [7] len/bytes
pdu[i++] = dbnr / 256; //0x00; // [8] dbnum
pdu[i++] = dbnr & 0x0ff; //0x01; // [9] dbnum
pdu[i++] = getOrg(org); //10
pdu[i] = ((start_adr*8)/0x010000) & 0x0ff; //0x00; // [11] start adr/bits
if (plc_type == S7_200) pdu[i] = start_adr / 0x10000;
i++;
pdu[i++] = ((start_adr*8)/0x0100) & 0x0ff; //0x00; // [12] start adr/bits
pdu[i++] = (start_adr*8) & 0x0ff; //0x00; // [13] start adr/bits
ret = write_iso(pdu,i);
if(ret < 0)
{
rlDebugPrintf("fetch:write_iso error ret==%d -> return -1\n", ret);
return ret;
}
ret = read_iso(pdu);
if(ret < 0)
{
rlDebugPrintf("fetch:read_iso error ret==%d -> return -1\n", ret);
return ret;
}
if(pdu[15] != 0x04)
{
rlDebugPrintf("fetch:pdu[15]=%d is not equal 0x04-> return -1\n", pdu[15]);
return -1;
}
if(pdu[16] != 0x01)
{
rlDebugPrintf("fetch:pdu[16]=%d is not equal 0x04-> return -1\n", pdu[16]);
return -1;
}
i = 21;
if(ret < i+len_byte) return -1;
for(int ibuf = 0; ibuf < len_byte; ibuf++)
{
buf[ibuf] = pdu[i++];
}
}
rlDebugPrintf("fetch:success len_byte=%d\n", len_byte);
return len_byte;
}
int rlSiemensTCP::getConnectBlock ( unsigned char *  connect_block)

Definition at line 65 of file rlsiemenstcp.cpp.

{
memcpy(connect_block,cb,sizeof(cb));
return 0;
}
int rlSiemensTCP::getDefaultConnectBlock ( unsigned char *  connect_block)
 

Definition at line 50 of file rlsiemenstcp.cpp.

{
static const unsigned char default_connect_block[] =
{3,0,0,22,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,2,1 ,0 ,0xC2,2,0 ,1 ,0xC0,1,9};
memcpy(connect_block,default_connect_block,sizeof(default_connect_block));
return 22;
}
int rlSiemensTCP::getOrg ( int  org)
private

Definition at line 157 of file rlsiemenstcp.cpp.

{
int ret;
switch(org)
{
case ORG_DB: ret = 0x84; break; //[10] Datenbaustein
case ORG_M: ret = 0x83; break; //[10] Merker
case ORG_E: ret = 0x81; break; //[10] Eingang
case ORG_A: ret = 0x82; break; //[10] Ausgang
case ORG_PEPA: ret = 0x80; break; //[10] Peripheral Area R/W [tested by VSA]
case ORG_Z: ret = 0x84; break; //[10] not tested
case ORG_T: ret = 29; break; //[10] Timer
default: return 0x83; break;
}
return ret;
}
int rlSiemensTCP::read_iso ( unsigned char *  buf)
private

Definition at line 523 of file rlsiemenstcp.cpp.

{
int i,ret,len;
ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
if(ret < 0)
{
rlDebugPrintf("read_iso:failure to read iso header ret=%d -> disconnecting\n", ret);
return ret;
}
if(ih.version != 3)
{
rlDebugPrintf("read_iso:header vesion mismatch version==%d -> disconnecting\n", ret);
return -1;
}
len = ih.length_high*256 + ih.length_low - 4;
if(len <= 0)
{
rlDebugPrintf("read_iso:len==%d from iso header is negative -> disconnecting\n", len);
return -1;
}
if(len > (int) sizeof(pdu))
{
rlDebugPrintf("read_iso:len==%d from iso header is larger than max PDU size -> disconnecting\n", len);
return -1;
}
ret = rlSocket::read(buf,len,TIMEOUT);
if(ret < 0)
{
rlDebugPrintf("read_iso:read buf got timeout -> disconnecting\n");
return ret;
}
{
::printf("read_iso() len=%d\n", len);
for(i=0; i<len; i++) ::printf("%02x,",buf[i]);
::printf("\n");
}
return len;
}
int rlSiemensTCP::setConnectBlock ( const unsigned char *  connect_block)

Definition at line 58 of file rlsiemenstcp.cpp.

{
memcpy(cb,connect_block,sizeof(cb));
use_cb = 1;
return 0;
}
int rlSiemensTCP::write ( int  org,
int  dbnr,
int  start_adr,
int  length,
const unsigned char *  buf,
int  function = WriteByte 
)

Definition at line 174 of file rlsiemenstcp.cpp.

{
int i,ibuf,ret,len_byte,length;
if(rlSocket::isConnected() == 0) return -1;
len_byte = len;
if(len_byte > (int) sizeof(pdu)) return -1;
//if(org == ORG_DB) len_byte *= 2;
//if(org == ORG_Z) len_byte *= 2;
//if(org == ORG_T) len_byte *= 2;
if((plc_type == S5 || plc_type == S7_300 || plc_type == S7_400) && fetch_write == 1)
{
rlDebugPrintf("using fetch_write\n");
length = sizeof(ih) + sizeof(wh) + len_byte;
unsigned char total_buf[sizeof(ih) + sizeof(wh) + sizeof(pdu)];
ih.version = 3;
ih.reserved = 0;
ih.length_high = length / 256;
ih.length_low = length & 0x0ff;
wh.ident[0] = 'S';
wh.ident[1] = '5';
wh.header_len = 16;
wh.op_code = 3;
wh.org_block = (unsigned char) org;
wh.dbnr = (unsigned char) dbnr;
wh.start_adr[0] = (unsigned char) start_adr / 256;
wh.start_adr[1] = (unsigned char) start_adr & 0x0ff;;
wh.len[0] = (unsigned char) len / 256;
wh.len[1] = (unsigned char) len & 0x0ff;;
wh.spare1 = 0x0ff;
memcpy(total_buf, &ih, sizeof(ih));
memcpy(total_buf+sizeof(ih), &wh, sizeof(wh));
memcpy(total_buf+sizeof(ih)+sizeof(wh), buf, len_byte);
ret = rlSocket::write(total_buf, sizeof(ih)+sizeof(wh)+len_byte);
rlDebugPrintf("write total_buf ret=%d\n",ret);
if(ret < 0) return ret;
/*
ret = rlSocket::write(&ih,sizeof(ih));
rlDebugPrintf("write ih ret=%d\n",ret);
if(ret < 0) return ret;
ret = rlSocket::write(&wh,sizeof(wh));
rlDebugPrintf("write wh ret=%d\n",ret);
if(ret < 0) return ret;
ret = rlSocket::write(buf,len_byte);
rlDebugPrintf("write buf ret=%d\n",ret);
if(ret < 0) return ret;
*/
ret = rlSocket::read(&ih,sizeof(ih),TIMEOUT);
rlDebugPrintf("read ih ret=%d\n",ret);
if(ret <= 0) return ret;
ret = rlSocket::read(&wa,sizeof(wa),TIMEOUT);
rlDebugPrintf("read wa ret=%d\n",ret);
if(ret <= 0) return ret;
if(wa.error_block != 0) return -1;
}
else
{
rlDebugPrintf("not using fetch_write\n");
i = 0;
pdu[i++] = 0x02;
pdu[i++] = 0xF0;
pdu[i++] = 0x80;
pdu[i++] = 0x32;
pdu[i++] = 0x01;
pdu[i++] = 0x00;
pdu[i++] = 0x00;
pdu[i++] = 0x00;
pdu[i++] = 0x00;
pdu[i++] = 0x00;
// The S7 update by Aljosa Merljak was tested on S7_200 only
// You could set your plc_type to S7_200 also, even if you have S7_300 || S7_400
// But only the else part has been tested with S7_300 and S7_400 up to now
//if(plc_type == S7_200)
// Hi Ken, currently only S7_200 was tested with this. But try if this also works with S7_400
if(plc_type >0) // works for all known plc_type == S7_200 || plc_type == S7_300 || plc_type == S7_400)
{
ret = 0;
switch(function)
{
case WriteBit: ret = write_bit (i, org, dbnr, start_adr, len, buf); break;
case WriteByte: ret = write_byte (i, org, dbnr, start_adr, len, buf); break;
}
if(ret < 0) return ret;
}
else // will only work for WriteByte with len_byte = 4
{
pdu[i++] = 0x0E;
pdu[i++] = 0x00;
pdu[i++] = 0x08;
pdu[i++] = 0x05; //0 write
pdu[i++] = 0x01; //1
pdu[i++] = 0x12; //2
pdu[i++] = 0x0A; //3
pdu[i++] = 0x10; //4
pdu[i++] = 0x02; //5
pdu[i++] = len_byte / 256; //6 0x00;
pdu[i++] = len_byte & 0x0ff; //7 0x04;
pdu[i++] = dbnr / 256; //8 0x00;
pdu[i++] = dbnr & 0x0ff; //9 0x00;
pdu[i++] = getOrg(org); //10
pdu[i++] = ((start_adr*8)/0x010000) & 0x0ff; //0x00; // [11] start adr/bits
pdu[i++] = ((start_adr*8)/0x0100) & 0x0ff; //0x00; // [12] start adr/bits
pdu[i++] = (start_adr*8) & 0x0ff; //0x00; // [13] start adr/bits
pdu[i++] = 0x00;
pdu[i++] = 0x04;
pdu[i++] = 0x00;
pdu[i++] = 0x20;
for(ibuf=0; ibuf<len_byte; ibuf++)
{
pdu[i++] = buf[ibuf];
if(i > (int) sizeof(pdu)) return -1;
}
}
ret = write_iso(pdu,i);
if(ret < 0) return ret;
ret = read_iso(pdu);
if(ret < 0) return ret;
if(pdu[15] != 0x05) return -1;
if(pdu[16] != 0x01) return -1;
// CODE from Víctor Centelles
if(pdu[17] != 0xff)
{
if(pdu[17] == 0x0a){
fprintf( stderr, " > Error: Trying to access a DB that does not exist\n");
fprintf( stderr, "          Please, check that DB is set.   (error code: 10 (0x0a))\n");
return -(pdu[17]);
}
else if(pdu[17] == 0x05){
fprintf(stderr, " > Error: Trying to access an address that does not exist.\n");
fprintf(stderr, "          Please, check the address range. (error code: 5 (0x05))\n");
return -(pdu[17]);
}
else if(pdu[17] == 0x07){
fprintf(stderr, " > Error: the write data size doesn't fit item size\n"); // NO TESTED!!!
fprintf(stderr, "          Please, check the data size.     (error code: 7 (0x07))\n");
return -(pdu[17]);
}
else{
fprintf(stderr, " > Error: unknown error  (código %x!=0xff)\n", pdu[17]);
return -(pdu[17]);
}
}
}
return len_byte;
}
int rlSiemensTCP::write_bit ( int &  i,
int  org,
int  dbnr,
int  start_adr,
int  len,
const unsigned char *  buf 
)
private

Definition at line 329 of file rlsiemenstcp.cpp.

{
int j;
pdu[i++] = 14 + 12 * (len - 1);
pdu[i++] = 0x00;
pdu[i++] = 6 * len - 1;
pdu[i++] = 0x05;
pdu[i++] = len;
for(j=0; j<len; j++)
{
pdu[i++] = 0x12;
pdu[i++] = 0x0a;
pdu[i++] = 0x10;
pdu[i++] = 0x01;
pdu[i++] = len / 256; //6 0x00;
pdu[i++] = 0x01; //7 number of bytes in group
pdu[i++] = dbnr / 256; //8 0x00;
pdu[i++] = dbnr & 0x0ff; //9 0x00;
pdu[i++] = getOrg(org); //10
pdu[i++] = ((start_adr / 8)/0x010000) & 0x0ff;
pdu[i++] = (start_adr / 0x0100) & 0x0ff; //0x00; // [12] start adr/bits
pdu[i++] = (start_adr + j) & 0x0ff; //0x00; // [13] start adr/bits
}
for(j=0; j<len; j++)
{
pdu[i++] = 0x00;
pdu[i++] = 0x03;
pdu[i++] = 0x00;
pdu[i++] = 0x01;
pdu[i++] = (buf[j]>0) ? 0x01 : 0x00;
if(j < len - 1 ) pdu[i++] = 0x00;
if(i > (int) sizeof(pdu)) return -1;
}
return i;
}
int rlSiemensTCP::write_byte ( int &  i,
int  org,
int  dbnr,
int  start_adr,
int  length,
const unsigned char *  buf 
)
private

Definition at line 365 of file rlsiemenstcp.cpp.

{
pdu[i++] = 0x0e;
pdu[i++] = 0x00;
pdu[i++] = 5 + len - 1;
pdu[i++] = 0x05;
pdu[i++] = 0x01;
pdu[i++] = 0x12;
pdu[i++] = 0x0a;
pdu[i++] = 0x10;
pdu[i++] = 0x02;
pdu[i++] = len / 256; //6 0x00;
pdu[i++] = len & 0x0ff; //7 number of bytes
pdu[i++] = dbnr / 256; //8 0x00;
pdu[i++] = dbnr & 0x0ff; //9 0x00;
pdu[i++] = getOrg(org); //10
pdu[i++] = start_adr /0x10000 & 0x0ff;
pdu[i++] = ((start_adr*8)/0x0100) & 0x0ff; //0x00; // [12] start adr/bits
pdu[i++] = (start_adr*8) & 0x0ff; //0x00; // [13] start adr/bits
pdu[i++] = 0x00;
pdu[i++] = 0x04;
pdu[i++] = (len * 8) / 256;
pdu[i++] = (len * 8) & 0xff;
for(int ibuf=0; ibuf<len; ibuf++)
{
pdu[i++] = buf[ibuf];
if(i > (int) sizeof(pdu)) return -1;
}
return i;
}
int rlSiemensTCP::write_iso ( unsigned char *  buf,
int  len 
)
private

Definition at line 569 of file rlsiemenstcp.cpp.

{
int i,ret;
if(len > (int) sizeof(pdu)) return -1;
if(rlSocket::isConnected() == 0) return -1;
// speedup siemens communication as suggested by Vincent Segui Pascual
// do only 1 write
unsigned char total_buf[sizeof(ih)+sizeof(pdu)];
ih.version = 3;
ih.reserved = 0;
ih.length_high = (len+4) / 256;
ih.length_low = (len+4) & 0x0ff;
memcpy(total_buf, &ih, sizeof(ih));
memcpy(total_buf + sizeof(ih), buf, sizeof(ih)+len);
ret = rlSocket::write(total_buf, sizeof(ih)+len);
if(ret < 0)
{
rlDebugPrintf("write_iso:failure to write buf -> disconnecting\n");
return ret;
}
/*
ih.version = 3;
ih.reserved = 0;
ih.length_high = (len+4) / 256;
ih.length_low = (len+4) & 0x0ff;
ret = rlSocket::write(&ih,sizeof(ih));
if(ret < 0)
{
rlDebugPrintf("write_iso:failure to write iso header -> disconnecting\n");
rlSocket::disconnect();
return ret;
}
ret = rlSocket::write(buf,len);
if(ret < 0)
{
rlDebugPrintf("write_iso:failure to write buf -> disconnecting\n");
rlSocket::disconnect();
return ret;
}
*/
{
::printf("write_iso() len=%d\n", len);
for(i=0; i<len; i++) ::printf("%02x,",buf[i]);
::printf("\n");
}
return len;
}

Member Data Documentation

unsigned char rlSiemensTCP::cb[22]
private

Definition at line 247 of file rlsiemenstcp.h.

FA rlSiemensTCP::fa
private

Definition at line 240 of file rlsiemenstcp.h.

int rlSiemensTCP::fetch_write
private

Definition at line 244 of file rlsiemenstcp.h.

FH rlSiemensTCP::fh
private

Definition at line 239 of file rlsiemenstcp.h.

int rlSiemensTCP::function
private

Definition at line 242 of file rlsiemenstcp.h.

IH rlSiemensTCP::ih
private

Definition at line 241 of file rlsiemenstcp.h.

unsigned char rlSiemensTCP::pdu[2048]
private

Definition at line 245 of file rlsiemenstcp.h.

int rlSiemensTCP::plc_type
private

Definition at line 243 of file rlsiemenstcp.h.

int rlSiemensTCP::rack_slot
private

Definition at line 242 of file rlsiemenstcp.h.

int rlSiemensTCP::use_cb
private

Definition at line 246 of file rlsiemenstcp.h.

WA rlSiemensTCP::wa
private

Definition at line 238 of file rlsiemenstcp.h.

WH rlSiemensTCP::wh
private

Definition at line 237 of file rlsiemenstcp.h.


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