|
rllib
1
|
#include <rlsiemenstcp.h>


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 { S7_200 = 1, S7_300 = 2, S7_400 = 3, S5 = 4, RACK_SLOT = 5 } |
| enum | SiemensFunctionCodes { WriteBit = 1, WriteByte = 2 } |
Public Member Functions | |
| rlSiemensTCP (const char *adr, int _plc_type, int _fetch_write=1, int function=-1, int rack_slot=-1) | |
| virtual | ~rlSiemensTCP () |
| 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) |
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] |
class for communication with Siemens PLC's via TCP
Definition at line 29 of file rlsiemenstcp.h.
| enum rlSiemensTCP::ORG |
Definition at line 50 of file rlsiemenstcp.h.
| rlSiemensTCP::rlSiemensTCP | ( | const char * | adr, |
| int | _plc_type, | ||
| int | _fetch_write = 1, |
||
| int | function = -1, |
||
| int | rack_slot = -1 |
||
| ) |
Definition at line 37 of file rlsiemenstcp.cpp.
| rlSiemensTCP::~rlSiemensTCP | ( | ) | [virtual] |
Definition at line 47 of file rlsiemenstcp.cpp.
{
rlSocket::disconnect();
}
| void rlSiemensTCP::doConnect | ( | ) | [private] |
Definition at line 52 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 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 (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 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;
}
}
rlSocket::disconnect();
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 357 of file rlsiemenstcp.cpp.
{
int i,ret,len_byte,length;
if(rlSocket::isConnected() == 0) doConnect();
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.ident_op_code = 1;
fh.op_code_len = 3;
fh.op_code = 5;
fh.ident_org_block = 3;
fh.len_org_block = 8;
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;
fh.spare1_len = 2;
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::getOrg | ( | int | org | ) | [private] |
Definition at line 128 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 = 0x84; break; //[10] not tested
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 476 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);
rlSocket::disconnect();
return ret;
}
if(ih.version != 3)
{
rlDebugPrintf("read_iso:header vesion mismatch version==%d -> disconnecting\n", ret);
rlSocket::disconnect();
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);
rlSocket::disconnect();
return -1;
}
if(len > (int) sizeof(pdu))
{
rlDebugPrintf("read_iso:len==%d from iso header is larger than max PDU size -> disconnecting\n", len);
rlSocket::disconnect();
return -1;
}
ret = rlSocket::read(buf,len,TIMEOUT);
if(ret < 0)
{
rlDebugPrintf("read_iso:read buf got timeout -> disconnecting\n");
rlSocket::disconnect();
return ret;
}
if(rlDebugPrintfState != 0)
{
::printf("read_iso() len=%d\n", len);
for(i=0; i<len; i++) ::printf("%02x,",buf[i]);
::printf("\n");
}
return len;
}
| int rlSiemensTCP::write | ( | int | org, |
| int | dbnr, | ||
| int | start_adr, | ||
| int | length, | ||
| const unsigned char * | buf, | ||
| int | function = WriteByte |
||
| ) |
Definition at line 145 of file rlsiemenstcp.cpp.
{
int i,ibuf,ret,len_byte,length;
if(rlSocket::isConnected() == 0) doConnect();
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)
{
rlDebugPrintf("using fetch_write\n");
length = sizeof(ih) + sizeof(wh) + len_byte;
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.ident_op_code = 1;
wh.op_code_len = 3;
wh.op_code = 3;
wh.ident_org_block = 3;
wh.len_org_block = 8;
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;
wh.spare1_len = 2;
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 == 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
{
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 290 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 326 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; //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 522 of file rlsiemenstcp.cpp.
{
int i,ret;
if(rlSocket::isConnected() == 0) doConnect();
if(rlSocket::isConnected() == 0) return -1;
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;
}
if(rlDebugPrintfState != 0)
{
::printf("write_iso() len=%d\n", len);
for(i=0; i<len; i++) ::printf("%02x,",buf[i]);
::printf("\n");
}
return len;
}
FA rlSiemensTCP::fa [private] |
Definition at line 138 of file rlsiemenstcp.h.
int rlSiemensTCP::fetch_write [private] |
Definition at line 142 of file rlsiemenstcp.h.
FH rlSiemensTCP::fh [private] |
Definition at line 137 of file rlsiemenstcp.h.
int rlSiemensTCP::function [private] |
Definition at line 140 of file rlsiemenstcp.h.
IH rlSiemensTCP::ih [private] |
Definition at line 139 of file rlsiemenstcp.h.
unsigned char rlSiemensTCP::pdu[2048] [private] |
Definition at line 143 of file rlsiemenstcp.h.
int rlSiemensTCP::plc_type [private] |
Definition at line 141 of file rlsiemenstcp.h.
int rlSiemensTCP::rack_slot [private] |
Definition at line 140 of file rlsiemenstcp.h.
WA rlSiemensTCP::wa [private] |
Definition at line 136 of file rlsiemenstcp.h.
WH rlSiemensTCP::wh [private] |
Definition at line 135 of file rlsiemenstcp.h.
1.7.5.1