Initial Version
This commit is contained in:
112
ChangeLog
Normal file
112
ChangeLog
Normal file
@@ -0,0 +1,112 @@
|
||||
08/26/2003 partly unified versions for MPI adapter and IBH NetLink. Common stuff went into
|
||||
nodaveCommon.c.
|
||||
It should now work with S7-400 PLCs without a patch, but I've not tested this.
|
||||
09/19/2003 Found remedy to prevent hangups in nodaveIBH.c
|
||||
10/04/2003 Added the stuff for S7-200 over PPI cable.
|
||||
10/05/2003 Wrote a test program for S7-200 over PPI cable.
|
||||
|
||||
03/13/2004 New functions to load a program block from the CPU.
|
||||
03/14/2004 New area type system data (SD), daveArea_SD
|
||||
|
||||
03/26/2004 Retry PPI send, when response times out.
|
||||
|
||||
05/20/2004 Working ISO/TCP transport with CPs x43
|
||||
06/14/2004 Fixed a bug regarding initialization of MPI/TS adapter
|
||||
|
||||
09/09/2004 Applied patch for variable Profibus speed from Andrew Rostovtsew.
|
||||
The Profibus speed is a new parameter to daveNewInterface,
|
||||
so you will need to change existing programs :-(
|
||||
The parameter is only meaningful for the MPI protocol. It is meaningful for but
|
||||
not yet supported by nodaveIBH. For all other protocols, any integer will do.
|
||||
|
||||
09/09/2004 Partly applied patch for compilation under Windows using Cygwin. Non-inline
|
||||
data conversion functions replace the inlined ones and the byteswap.h from Linux.
|
||||
|
||||
09/12/2004 Implemented the read from multiple addresses.
|
||||
|
||||
10/10/2004 Made a unified version for all protocols (not yet IBH)
|
||||
Added targets: make install, make dynamic to Makefile
|
||||
12/01/2004 Fixed a bug in nodave.c that made compilers complain.
|
||||
12/08/2004 Make read of analog inputs and outputs of 2xx work.
|
||||
|
||||
12/09/2004 Rmoved some debug printf()s.
|
||||
12/09/2004 Found and fixed a bug in daveFreeResults(): The result set is provided by the
|
||||
application and not necessarily dynamic. So we shall not free() it.
|
||||
12/19/2004 First version for WIN32 and C
|
||||
01/11/2005 Some code cleanup. Can now load program blocks into CPU 315. Win32 version
|
||||
COM port settings fixed.
|
||||
01/16/2005 Fixed reception of SZL-lists and block lists that don't fir into a single PDU.
|
||||
01/26/2005 Multiple write implemented.
|
||||
01/31/2005 Fixed isotest4.c, which could not be compiled with most C-compilers but mine,
|
||||
however.
|
||||
02/06/2005 Added workarounds to run on ARM processors.
|
||||
02/12/2005 Integrated code for IBH NetLink.
|
||||
02/13/2005 Put benchmarks into a separate file.
|
||||
02/21/2005 Put program download and RUN/STOP functions into main test programs.
|
||||
03/03/2005 Added fix from Axel Kinting that speeds up connections via IBH-NetLink.
|
||||
03/03/2005 Added an option to set slot number in testISO_TCP.
|
||||
03/03/2005 Changed dword to longword in pascal/nodave.pas for Delphi compatibility.
|
||||
|
||||
03/18/2005 Added code to access S7-200 with PPI protocol over IBH/MHJ-NetLink gateways.
|
||||
03/18/2005 Changed unified benchmark code to use different memory areas on 200 or 300/400 CPUs.
|
||||
04/06/2005 renamed swap functions. When I began libnodave on little endian i386 and Linux, I used
|
||||
used Linux bswap functions. Then users (and later me) tried other systems without
|
||||
a bswap. I also cannot use inline functions in Pascal. So I made my own bswaps. Then
|
||||
I, made the core of my own swaps dependent of LITTLEENDIAN conditional to support also
|
||||
bigendien systems. Now I want to rename them from bswap to something else to avoid
|
||||
confusion for LINUX/UNIX users. The new names are swapIed_16 and swapIed_32. This
|
||||
shall say swap "if endianness differs". While I could have used similar functions
|
||||
from the network API (htons etc.) on Unix and Win32, they may not be present on
|
||||
e.g. microcontrollers.
|
||||
I highly recommend to use these functions even when writing software for big endian
|
||||
systems, where they effectively do nothing, as it will make your software portable.
|
||||
04/06/05 removed daveGetByte(), daveGetWORD(), daveGetWORDat(), getByteAt(), getInteger().
|
||||
I first named these function according to Linux gcc C or PLC data types. But the
|
||||
problem is that e.g. an INT on Siemens PLCs is a 16bit signed value. That's in turn
|
||||
a short on gcc, an integer on Turbo Pascal, Is it still an integer in Delphi? So the
|
||||
newer funtions are named after bit length and signedness of what they transfer to/from
|
||||
PLC data copies. So daveGetU16 means get an unsigned 16 bit value.
|
||||
04/10/05 Hope I fixed a bug in daveWriteBytes(), daveWriteBits(): In multiple write, if the
|
||||
data to be written is of odd length, a 0 byte is appended before further data
|
||||
follows. Versions 0.6.x appended such a byte to each write request if data length
|
||||
is odd, but this fails under some circumstances.
|
||||
This version appends the 0 byte only before further data is appended.
|
||||
04/11/05 Fixed some bugs in test programs: Test programs (and all other applications) may
|
||||
only retrieve data from internal buffer (via daveGetU8 etc.) if read result is 0.
|
||||
Otherwise they would read from an undefined pointer.
|
||||
04/21/05 renamed LITTLEENDIAN to LITTLE_ENDIAN because it seems to conflict with
|
||||
another #define in winsock2.h.
|
||||
04/29/05 Added a function to set Outputs in S7-200 when the PLC is in Stop mode. I called
|
||||
this function "daveForce", but it DOES not force the values in the sense that the
|
||||
forced state would override the result of the PLC program. Instead, as soon as you
|
||||
switch to RUN, these settings are of no more effect. When you switch back to stop,
|
||||
all outputs will be 0 again.
|
||||
05/06/05 Because some users reported difficulties to use the prebuilt .dll and .lib file
|
||||
created with Borland tools, I cared to add a .dll and .lib file compiled with MSVC.
|
||||
I could download a VCToolkitSetup and the Platform SDK from Microsoft for free.
|
||||
There is neither an IDE nor a make utility. So I used GNU-make and wine on Linux
|
||||
to find out how to build the .dll and test programs.
|
||||
The Makefile for GNU make is MAKEFILE.VC.WINE.
|
||||
I cannot write a Makefile for MS-make without having it. So, for people which want
|
||||
to use MSVC but cannot find out how to set options to the IDE or build a Makefile,
|
||||
I provide a batch file which will just rebuild all.
|
||||
05/11/05 Added a free function to dispose memory reserved by the library.
|
||||
08/05/05 Added a string copy function.
|
||||
08/06/05 Added daveGetProgramBlock() and daveFetMaxPDULen()
|
||||
08/06/05 Added a PERL interface and example code.
|
||||
08/07/05 Added a VB interface and example code.
|
||||
10/06/05 Added usage of Siemens libraries for transport.
|
||||
|
||||
03/30/06 Bug fixes for .NET
|
||||
05/15/06 Applied patch from Ken Wenzel for NETLink PRO
|
||||
05/15/06 Applied PERL patches from H.-J. Beie
|
||||
05/29/06 Bug fixes for AS511
|
||||
Version 0.8.4.5
|
||||
07/10/09 Changed readISOpacket for Win32 to select() before recv().
|
||||
07/10/09 Added closeSocket()
|
||||
07/10/09 Added daveCopyRAMtoROM
|
||||
07/12/09 Changed flags in setport.c. Older version does not work with recent Linux
|
||||
kernels.
|
||||
07/12/09 Removed C-Sharp subdirectory. These were my first experiments with that
|
||||
language.
|
||||
|
||||
75
Dot.NET/CS/simpleISO_TCP.cs
Normal file
75
Dot.NET/CS/simpleISO_TCP.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Very simple program to read from a 300/400 PLC via MPI adapter.
|
||||
This shall provide users with a simple starting point for their own
|
||||
applications.
|
||||
|
||||
Part of Libnodave, a free communication libray for Siemens S7 200/300/400
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with Libnodave; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
class test {
|
||||
static libnodave.daveOSserialType fds;
|
||||
static libnodave.daveInterface di;
|
||||
static libnodave.daveConnection dc;
|
||||
static int rack=0;
|
||||
static int slot=2;
|
||||
public static int Main (string[] args)
|
||||
{
|
||||
int i,a=0,j,res,b=0,c=0;
|
||||
float d=0;
|
||||
|
||||
fds.rfd=libnodave.openSocket(102,args[0]);
|
||||
fds.wfd=fds.rfd;
|
||||
if (fds.rfd>0) {
|
||||
di =new libnodave.daveInterface(fds, "IF1", 0, libnodave.daveProtoISOTCP, libnodave.daveSpeed187k);
|
||||
di.setTimeout(1000000);
|
||||
// res=di.initAdapter(); // does nothing in ISO_TCP. But call it to keep your programs indpendent of protocols
|
||||
// if(res==0) {
|
||||
dc = new libnodave.daveConnection(di,0 , rack, slot);
|
||||
if (0==dc.connectPLC()) {
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, null);
|
||||
if (res==0) {
|
||||
a=dc.getS32();
|
||||
b=dc.getS32();
|
||||
c=dc.getS32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: " + a);
|
||||
Console.WriteLine("FD4: " + b);
|
||||
Console.WriteLine("FD8: " + c);
|
||||
Console.WriteLine("FD12: " + d);
|
||||
} else
|
||||
Console.WriteLine("error "+res+" "+libnodave.daveStrerror(res));
|
||||
}
|
||||
dc.disconnectPLC();
|
||||
// }
|
||||
// di.disconnectAdapter(); // does nothing in ISO_TCP. But call it to keep your programs indpendent of protocols
|
||||
libnodave.closeSocket(fds.rfd);
|
||||
} else {
|
||||
Console.WriteLine("Couldn't open TCP connaction to "+args[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Version 0.8.4.5
|
||||
07/10/09 Added closeSocket()
|
||||
*/
|
||||
BIN
Dot.NET/CS/simpleISO_TCP.exe
Executable file
BIN
Dot.NET/CS/simpleISO_TCP.exe
Executable file
Binary file not shown.
70
Dot.NET/CS/simpleMPI.cs
Normal file
70
Dot.NET/CS/simpleMPI.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Very simple program to read from a 300/400 PLC via MPI adapter.
|
||||
This shall provide users with a simple starting point for their own
|
||||
applications.
|
||||
|
||||
Part of Libnodave, a free communication libray for Siemens S7 200/300/400
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with Libnodave; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
class test {
|
||||
static libnodave.daveOSserialType fds;
|
||||
static libnodave.daveInterface di;
|
||||
static libnodave.daveConnection dc;
|
||||
static int localMPI=0;
|
||||
static int plcMPI=2;
|
||||
public static int Main (string[] args)
|
||||
{
|
||||
int i,a=0,j,res,b=0,c=0;
|
||||
float d=0;
|
||||
|
||||
fds.rfd=libnodave.setPort(args[0],"38400",'O');
|
||||
fds.wfd=fds.rfd;
|
||||
if (fds.rfd>0) {
|
||||
di =new libnodave.daveInterface(fds, "IF1", localMPI, libnodave.daveProtoMPI, libnodave.daveSpeed187k);
|
||||
di.setTimeout(1000000);
|
||||
res=di.initAdapter();
|
||||
if(res==0) {
|
||||
dc = new libnodave.daveConnection(di,plcMPI, 0, 0);
|
||||
if (0==dc.connectPLC()) {
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, null);
|
||||
if (res==0) {
|
||||
a=dc.getS32();
|
||||
b=dc.getS32();
|
||||
c=dc.getS32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: " + a);
|
||||
Console.WriteLine("FD4: " + b);
|
||||
Console.WriteLine("FD8: " + c);
|
||||
Console.WriteLine("FD12: " + d);
|
||||
} else
|
||||
Console.WriteLine("error "+res+" "+libnodave.daveStrerror(res));
|
||||
}
|
||||
dc.disconnectPLC();
|
||||
}
|
||||
di.disconnectAdapter();
|
||||
libnodave.closePort(fds.rfd);
|
||||
} else {
|
||||
Console.WriteLine("Couldn't open serial port "+args[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BIN
Dot.NET/CS/simpleMPI.exe
Executable file
BIN
Dot.NET/CS/simpleMPI.exe
Executable file
Binary file not shown.
70
Dot.NET/CS/simplePPI.cs
Normal file
70
Dot.NET/CS/simplePPI.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Very simple program to read from a 200 PLC via PPI cable.
|
||||
This shall provide users with a simple starting point for their own
|
||||
applications.
|
||||
|
||||
Part of Libnodave, a free communication libray for Siemens S7 200/300/400
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with Libnodave; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
class test {
|
||||
static libnodave.daveOSserialType fds;
|
||||
static libnodave.daveInterface di;
|
||||
static libnodave.daveConnection dc;
|
||||
static int localPPI=0;
|
||||
static int plcPPI=2;
|
||||
public static int Main (string[] args)
|
||||
{
|
||||
int i,a=0,j,res,b=0,c=0;
|
||||
float d=0;
|
||||
|
||||
fds.rfd=libnodave.setPort(args[0],"9600",'E');
|
||||
fds.wfd=fds.rfd;
|
||||
if (fds.rfd>0) {
|
||||
di =new libnodave.daveInterface(fds, "IF1", localPPI, libnodave.daveProtoPPI, libnodave.daveSpeed187k);
|
||||
di.setTimeout(1000000);
|
||||
// res=di.initAdapter(); // does nothing in PPI. But call it to keep your programs indpendent of protocols
|
||||
// if(res==0) {
|
||||
dc = new libnodave.daveConnection(di,plcPPI, 0, 0);
|
||||
if (0==dc.connectPLC()) {
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, null);
|
||||
if (res==0) {
|
||||
a=dc.getS32();
|
||||
b=dc.getS32();
|
||||
c=dc.getS32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: " + a);
|
||||
Console.WriteLine("FD4: " + b);
|
||||
Console.WriteLine("FD8: " + c);
|
||||
Console.WriteLine("FD12: " + d);
|
||||
} else
|
||||
Console.WriteLine("error "+res+" "+libnodave.daveStrerror(res));
|
||||
}
|
||||
dc.disconnectPLC();
|
||||
// }
|
||||
// di.disconnectAdapter(); // does nothing in PPI. But call it to keep your programs indpendent of protocols
|
||||
libnodave.closePort(fds.rfd);
|
||||
} else {
|
||||
Console.WriteLine("Couldn't open serial port "+args[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BIN
Dot.NET/CS/simplePPI.exe
Executable file
BIN
Dot.NET/CS/simplePPI.exe
Executable file
Binary file not shown.
702
Dot.NET/CS/testMPI.cs
Normal file
702
Dot.NET/CS/testMPI.cs
Normal file
@@ -0,0 +1,702 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
class test {
|
||||
static void wait() {
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
Console.WriteLine("Usage: testMPI [-d] [-w] serial port.");
|
||||
Console.WriteLine("-w will try to write to Flag words. It will overwrite FB0 to FB15 (MB0 to MB15) !");
|
||||
Console.WriteLine("-d will produce a lot of debug messages.");
|
||||
Console.WriteLine("-b will run benchmarks. Specify -b and -w to run write benchmarks.");
|
||||
Console.WriteLine("-z will read some SZL list items (diagnostic information).");
|
||||
Console.WriteLine("-2 uses a slightly different version of the MPI protocol. Try it, if your Adapter doesn't work.");
|
||||
Console.WriteLine("-m will run a test for multiple variable reads.");
|
||||
Console.WriteLine("-c will write 0 to the PLC memory used in write tests.");
|
||||
Console.WriteLine("-n will test newly added functions.");
|
||||
Console.WriteLine("-a will read out everything from system state lists(SZLs).");
|
||||
Console.WriteLine("-s stops the PLC.");
|
||||
Console.WriteLine("-r tries to put the PLC in run mode.");
|
||||
Console.WriteLine("--readout read program and data blocks from PLC.");
|
||||
Console.WriteLine("--readoutall read all program and data blocks from PLC. Includes SFBs and SFCs.");
|
||||
Console.WriteLine("-<number> will set the speed of MPI/PROFIBUS network to this value (in kBaud). Default is 187. Supported values are 9, 19, 45, 93, 187, 500 and 1500.");
|
||||
Console.WriteLine("--mpi=<number> will use number as the MPI adddres of the PLC. Default is 2.");
|
||||
Console.WriteLine("--mpi2=<number> Use this option to test simultaneous connections to 2 PLCs.");
|
||||
Console.WriteLine(" It will use number as the MPI adddres of the 2nd PLC. Default is no 2nd PLC.");
|
||||
Console.WriteLine(" Most tests are executed with the first PLC. The first read test is also done with");
|
||||
Console.WriteLine(" with the 2nd one to demonstrate that this works.");
|
||||
Console.WriteLine("--local=<number> will set the local MPI adddres to number. Default is 0.");
|
||||
Console.WriteLine("--debug=<number> will set daveDebug to number.");
|
||||
//#ifdef UNIX_STYLE
|
||||
Console.WriteLine("Example: testMPI -w /dev/ttyS0");
|
||||
//#endif
|
||||
//#ifdef WIN_STYLE
|
||||
Console.WriteLine("Example: testMPI -w COM1");
|
||||
//#endif
|
||||
}
|
||||
|
||||
static int initSuccess=0;
|
||||
static int localMPI=0;
|
||||
static int plcMPI=2;
|
||||
static int plc2MPI=-1;
|
||||
static int adrPos=0;
|
||||
static int useProto=libnodave.daveProtoMPI;
|
||||
static int speed=libnodave.daveSpeed187k;
|
||||
static libnodave.daveOSserialType fds;
|
||||
static libnodave.daveInterface di;
|
||||
static libnodave.daveConnection dc;
|
||||
static bool doWrite=false;
|
||||
static bool doClear=false;
|
||||
static bool doRun=false;
|
||||
static bool doStop=false;
|
||||
static bool doWbit=false;
|
||||
static int wbit;
|
||||
static bool doSZLread=false;
|
||||
static bool doSZLreadAll=false;
|
||||
static bool doBenchmark=false;
|
||||
static bool doReadout=false;
|
||||
static bool doSFBandSFC=false;
|
||||
static bool doExperimental=false;
|
||||
static bool doMultiple=false;
|
||||
static bool doNewfunctions=false;
|
||||
|
||||
static void readSZL(libnodave.daveConnection dc, int id, int index) {
|
||||
int res, SZLid, indx, SZcount, SZlen,i,j,len;
|
||||
byte[] ddd=new byte[3000];
|
||||
Console.WriteLine(String.Format("Trying to read SZL-ID {0:X04}, index {1:X02}",id,index));
|
||||
res=dc.readSZL(id,index, ddd, 3000);
|
||||
Console.WriteLine("Function result: "+res+" "+libnodave.daveStrerror(res)+" len:"+dc.getAnswLen());
|
||||
|
||||
if (dc.getAnswLen()>=4) {
|
||||
len=dc.getAnswLen()-8;
|
||||
SZLid=libnodave.getU16from(ddd,0);
|
||||
indx=libnodave.getU16from(ddd,2);
|
||||
Console.WriteLine(String.Format("result SZL ID {0:X04}, index {1:X02}",SZLid,indx));
|
||||
int d=8;
|
||||
if (dc.getAnswLen()>=8) {
|
||||
SZlen=libnodave.getU16from(ddd,4);
|
||||
SZcount=libnodave.getU16from(ddd,6);
|
||||
Console.WriteLine(" "+SZcount+" elements of "+SZlen+" bytes");
|
||||
if(len>0){
|
||||
for (i=0;i<SZcount;i++){
|
||||
if(len>0){
|
||||
for (j=0; j<SZlen; j++){
|
||||
if(len>0){
|
||||
Console.Write(String.Format("{0:X02},",ddd[d]));
|
||||
d++;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
Console.WriteLine(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.WriteLine(" ");
|
||||
}
|
||||
|
||||
static void readSZLAll(libnodave.daveConnection dc) {
|
||||
byte[] d=new byte[1000];
|
||||
int res, SZLid, indx, SZcount, SZlen,i,j, rid, rind;
|
||||
|
||||
res=dc.readSZL(0,0, d, 1000);
|
||||
Console.WriteLine(" "+res+" "+dc.getAnswLen());
|
||||
if ((dc.getAnswLen())>=4) {
|
||||
SZLid=dc.getU16();
|
||||
indx=dc.getU16();
|
||||
Console.WriteLine(String.Format("result SZL ID {0:X04} index {1:X02}",SZLid,indx));
|
||||
if ((dc.getAnswLen())>=8) {
|
||||
SZlen=0x100*d[4]+d[5];
|
||||
SZcount=0x100*d[6]+d[7];
|
||||
Console.WriteLine("%d elements of %d bytes\n",SZcount,SZlen);
|
||||
for (i=0;i<SZcount;i++){
|
||||
rid=libnodave.getU16from(d,i*SZlen+8);
|
||||
rind=0;
|
||||
Console.WriteLine(String.Format("\nID:{0:X04} index {1:X02}",rid,rind));
|
||||
readSZL(dc, rid, rind);
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.WriteLine("\n");
|
||||
}
|
||||
|
||||
static void loadBlocksOfType(libnodave.daveConnection dc, int blockType, bool doReadout) {
|
||||
|
||||
int j, i, len, k;
|
||||
|
||||
int res;
|
||||
|
||||
byte[] blockBuffer=new byte[20000];
|
||||
byte[] dbe=new byte[2000];
|
||||
|
||||
j=dc.ListBlocksOfType(blockType, dbe);
|
||||
|
||||
if (j<0) {
|
||||
Console.WriteLine("error "+(-j)+" = " + libnodave.daveStrerror(-j));
|
||||
return;
|
||||
}
|
||||
string blockName=libnodave.blockName(blockType);
|
||||
Console.WriteLine(j+" blocks of type "+blockName);
|
||||
|
||||
for(i=0; i<j; i++) {
|
||||
int number=BitConverter.ToInt16(dbe,4*i+0);
|
||||
|
||||
Console.WriteLine(libnodave.blockName(blockType)+" "+number);
|
||||
|
||||
if(doReadout) {
|
||||
len=1111;
|
||||
dc.getProgramBlock(blockType, number, blockBuffer, ref(len));
|
||||
blockName=libnodave.blockName(blockType)+number+".mc7";
|
||||
FileStream fs= new FileStream(blockName,FileMode.CreateNew);
|
||||
BinaryWriter w= new BinaryWriter(fs);
|
||||
for (k=0; k<len; k++)
|
||||
w.Write(blockBuffer[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void rBenchmark(libnodave.daveConnection dc, int bmArea) {
|
||||
int i,res,maxReadLen,areaNumber;
|
||||
double usec;
|
||||
long t1, t2;
|
||||
libnodave.resultSet rs=new libnodave.resultSet();
|
||||
maxReadLen=dc.getMaxPDULen()-46;
|
||||
areaNumber=0;
|
||||
if(bmArea==libnodave.daveDB) areaNumber=1;
|
||||
Console.WriteLine("Now going to do read benchmark with minimum block length of 1.\n");
|
||||
t1=Environment.TickCount;
|
||||
for (i=1;i<101;i++) {
|
||||
dc.readBytes(bmArea, areaNumber,0, 1, null);
|
||||
if (i%10==0) {
|
||||
Console.Write("..."+i);
|
||||
}
|
||||
}
|
||||
t2=Environment.TickCount;
|
||||
usec = 0.001 * (t2 - t1);
|
||||
Console.WriteLine(" 100 reads took "+usec+" secs.");
|
||||
Console.WriteLine("Now going to do read benchmark with shurely supported block length "+maxReadLen);
|
||||
t1=Environment.TickCount;
|
||||
for (i=1;i<101;i++) {
|
||||
dc.readBytes(bmArea, areaNumber, 0, maxReadLen, null);
|
||||
if (i%10==0) {
|
||||
Console.Write("..."+i);
|
||||
}
|
||||
}
|
||||
t2=Environment.TickCount;
|
||||
usec = 0.001 * (t2 - t1);
|
||||
Console.WriteLine(" 100 reads took "+usec+" secs. ");
|
||||
|
||||
Console.WriteLine("Now going to do read benchmark with 5 variables in a single request.");
|
||||
Console.WriteLine("running...");
|
||||
|
||||
t1=Environment.TickCount;
|
||||
|
||||
for (i=1;i<101;i++) {
|
||||
libnodave.PDU p=dc.prepareReadRequest();
|
||||
p.addVarToReadRequest(libnodave.daveInputs,0,0,6);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,0,6);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,6,6);
|
||||
p.addVarToReadRequest(bmArea,areaNumber,4,54);
|
||||
p.addVarToReadRequest(bmArea,areaNumber,4,4);
|
||||
res=dc.execReadRequest(p, rs);
|
||||
if (res!=0) Console.WriteLine("\nerror "+res+" = "+libnodave.daveStrerror(res));
|
||||
if (i%10==0) {
|
||||
Console.Write("..."+i);
|
||||
}
|
||||
}
|
||||
t2=Environment.TickCount;
|
||||
usec = 0.001 * (t2 - t1);
|
||||
Console.WriteLine(" 100 reads took "+usec+" secs.");
|
||||
}
|
||||
|
||||
public static int Main (string[] args)
|
||||
{
|
||||
int i,a=0,j,res,b=0,c=0;
|
||||
float d=0;
|
||||
byte[] buf1=new byte[libnodave.davePartnerListSize];
|
||||
|
||||
if (args.Length <1) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (args[adrPos][0]=='-') {
|
||||
if (args[adrPos].StartsWith("--debug=")) {
|
||||
libnodave.daveSetDebug(Convert.ToInt32(args[adrPos].Substring(8)));
|
||||
Console.WriteLine("setting debug to: ",Convert.ToInt32(args[adrPos].Substring(8)));
|
||||
} else if (args[adrPos].StartsWith("-d")) {
|
||||
libnodave.daveSetDebug(libnodave.daveDebugAll);
|
||||
} else if (args[adrPos].StartsWith("-s")) {
|
||||
doStop=true;
|
||||
} else if (args[adrPos].StartsWith("-w")) {
|
||||
doWrite=true;
|
||||
} else if (args[adrPos].StartsWith("-b")) {
|
||||
doBenchmark=true;
|
||||
} else if (args[adrPos].StartsWith("--readoutall")) {
|
||||
doReadout=true;
|
||||
doSFBandSFC=true;
|
||||
} else if (args[adrPos].StartsWith("--readout")) {
|
||||
doReadout=true;
|
||||
} else if (args[adrPos].StartsWith("-r")) {
|
||||
doRun=true;
|
||||
} else if (args[adrPos].StartsWith("-e")) {
|
||||
doExperimental=true;
|
||||
} else if (args[adrPos].StartsWith("--local=")) {
|
||||
localMPI=Convert.ToInt32(args[adrPos].Substring(8));
|
||||
Console.WriteLine("setting local MPI address to: "+localMPI);
|
||||
} else if (args[adrPos].StartsWith("--mpi=")) {
|
||||
plcMPI=Convert.ToInt32(args[adrPos].Substring(6));
|
||||
Console.WriteLine("setting MPI address of PLC to: "+plcMPI);
|
||||
} else if (args[adrPos].StartsWith("--mpi2=")) {
|
||||
plc2MPI=Convert.ToInt32(args[adrPos].Substring(7));
|
||||
Console.WriteLine("setting MPI address of 2md PLC to: "+plc2MPI);
|
||||
} else if (args[adrPos].StartsWith("--wbit=")) {
|
||||
wbit=Convert.ToInt32(args[adrPos].Substring(7));
|
||||
Console.WriteLine("setting bit number: "+wbit);
|
||||
doWbit=true;
|
||||
} else if (args[adrPos].StartsWith("-z")) {
|
||||
doSZLread=true;
|
||||
} else if (args[adrPos].StartsWith("-a")) {
|
||||
doSZLreadAll=true;
|
||||
} else if (args[adrPos].StartsWith("-m")) {
|
||||
doMultiple=true;
|
||||
} else if (args[adrPos].StartsWith("-c")) {
|
||||
doClear=true;
|
||||
} else if (args[adrPos].StartsWith("-n")) {
|
||||
doNewfunctions=true;
|
||||
} else if (args[adrPos].StartsWith("-2")) {
|
||||
useProto=libnodave.daveProtoMPI2;
|
||||
} else if (args[adrPos].StartsWith("-3")) {
|
||||
useProto=libnodave.daveProtoMPI3;
|
||||
} else if (args[adrPos].StartsWith("-9")) {
|
||||
speed=libnodave.daveSpeed9k;
|
||||
} else if (args[adrPos].StartsWith("-19")) {
|
||||
speed=libnodave.daveSpeed19k;
|
||||
} else if (args[adrPos].StartsWith("-45")) {
|
||||
speed=libnodave.daveSpeed45k;
|
||||
} else if (args[adrPos].StartsWith("-93")) {
|
||||
speed=libnodave.daveSpeed93k;
|
||||
} else if (args[adrPos].StartsWith("-500")) {
|
||||
speed=libnodave.daveSpeed500k;
|
||||
} else if (args[adrPos].StartsWith("-1500")) {
|
||||
speed=libnodave.daveSpeed1500k;
|
||||
}
|
||||
|
||||
adrPos++;
|
||||
if (args.Length<=adrPos) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fds.rfd=libnodave.setPort(args[adrPos],"38400",'O');
|
||||
fds.wfd=fds.rfd;
|
||||
if (fds.rfd>0) {
|
||||
di =new libnodave.daveInterface(fds, "IF1", localMPI, useProto, speed);
|
||||
di.setTimeout(5000000);
|
||||
for (i=0; i<3; i++) {
|
||||
if (0==di.initAdapter()) {
|
||||
initSuccess=1;
|
||||
// a= libnodave.daveListReachablePartners(di,buf1);
|
||||
a= di.listReachablePartners(buf1);
|
||||
Console.WriteLine("daveListReachablePartners List length: "+a);
|
||||
if (a>0) {
|
||||
for (j=0;j<a;j++) {
|
||||
if (buf1[j]==libnodave.daveMPIReachable)
|
||||
Console.WriteLine("Device at address: "+j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else di.disconnectAdapter();
|
||||
}
|
||||
if (initSuccess==0) {
|
||||
Console.WriteLine("Couldn't connect to Adapter!.\n Please try again. You may also try the option -2 for some adapters.");
|
||||
return -3;
|
||||
}
|
||||
|
||||
dc = new libnodave.daveConnection(di,plcMPI,0,0);
|
||||
|
||||
if (0==dc.connectPLC()) {;
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, null);
|
||||
if (res==0) {
|
||||
a=dc.getS32();
|
||||
b=dc.getS32();
|
||||
c=dc.getS32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: " + a);
|
||||
Console.WriteLine("FD4: " + b);
|
||||
Console.WriteLine("FD8: " + c);
|
||||
Console.WriteLine("FD12: " + d);
|
||||
} else
|
||||
Console.WriteLine("error "+res+" "+libnodave.daveStrerror(res));
|
||||
|
||||
if(doExperimental) {
|
||||
Console.WriteLine("Trying to read outputs");
|
||||
res=dc.readBytes(libnodave.daveOutputs, 0, 0, 2, null);
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
if (res==0) {
|
||||
Console.Write("Bytes:");
|
||||
for (b=0; b<dc.getAnswLen(); b++) {
|
||||
c=dc.getU8();
|
||||
Console.Write(String.Format(" {0:X0}, ",c));
|
||||
}
|
||||
Console.WriteLine("");
|
||||
}
|
||||
a=0x01;
|
||||
Console.WriteLine("Trying to write outputs");
|
||||
res=dc.writeBytes(libnodave.daveOutputs, 0, 0, 1, BitConverter.GetBytes(a));
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
libnodave.daveSetDebug(libnodave.daveDebugAll);
|
||||
res=dc.force200(libnodave.daveOutputs,0,0);
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
libnodave.daveSetDebug(0);
|
||||
res=dc.force200(libnodave.daveOutputs,0,1);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
|
||||
res=dc.force200(libnodave.daveOutputs,0,2);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,0,3);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,1,4);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,2,5);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,3,7);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
Console.WriteLine("Trying to read outputs again\n");
|
||||
res=dc.readBytes(libnodave.daveOutputs, 0, 0, 4, null);
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
if (res==0) {
|
||||
Console.Write("Bytes:");
|
||||
for (b=0; b<dc.getAnswLen(); b++) {
|
||||
c=dc.getU8();
|
||||
Console.Write(String.Format(" {0:X0}, ",c));
|
||||
}
|
||||
Console.WriteLine("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(doWrite) {
|
||||
Console.WriteLine("Now we write back these data after incrementing the integers by 1,2 and 3 and the float by 1.1.\n");
|
||||
wait();
|
||||
/*
|
||||
Attention! you need to daveSwapIed little endian variables before using them as a buffer for
|
||||
daveWriteBytes() or before copying them into a buffer for daveWriteBytes()!
|
||||
*/
|
||||
a=libnodave.daveSwapIed_32(a+1);
|
||||
dc.writeBytes(libnodave.daveFlags,0,0,4,BitConverter.GetBytes(a));
|
||||
b=libnodave.daveSwapIed_32(b+2);
|
||||
dc.writeBytes(libnodave.daveFlags,0,4,4,BitConverter.GetBytes(b));
|
||||
c=libnodave.daveSwapIed_32(c+3);
|
||||
dc.writeBytes(libnodave.daveFlags,0,8,4,BitConverter.GetBytes(c));
|
||||
d=libnodave.toPLCfloat(d+1.1f);
|
||||
dc.writeBytes(libnodave.daveFlags,0,12,4,BitConverter.GetBytes(d));
|
||||
/*
|
||||
* Read back and show the new values, so users may notice the difference:
|
||||
*/
|
||||
dc.readBytes(libnodave.daveFlags,0,0,16, null);
|
||||
a=dc.getU32();
|
||||
b=dc.getU32();
|
||||
c=dc.getU32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: "+a);
|
||||
Console.WriteLine("FD4: "+b);
|
||||
Console.WriteLine("FD8: "+c);
|
||||
Console.WriteLine("FD12: "+d);
|
||||
} // doWrite
|
||||
|
||||
if(doClear) {
|
||||
Console.WriteLine("Now writing 0 to the bytes FB0...FB15.\n");
|
||||
// wait();
|
||||
byte[] aa={0,0,0,0};
|
||||
dc.writeBytes(libnodave.daveFlags,0,0,4,aa);
|
||||
dc.writeBytes(libnodave.daveFlags,0,4,4,aa);
|
||||
dc.writeBytes(libnodave.daveFlags,0,8,4,aa);
|
||||
dc.writeBytes(libnodave.daveFlags,0,12,4,aa);
|
||||
dc.readBytes(libnodave.daveFlags,0,0,16, null);
|
||||
a=dc.getU32();
|
||||
b=dc.getU32();
|
||||
c=dc.getU32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: "+a);
|
||||
Console.WriteLine("FD4: "+b);
|
||||
Console.WriteLine("FD8: "+c);
|
||||
Console.WriteLine("FD12: "+d);
|
||||
} // doClear
|
||||
|
||||
if(doSZLread) {
|
||||
readSZL(dc,0x92,0x0);
|
||||
readSZL(dc,0xB4,0x1024);
|
||||
readSZL(dc,0x111,0x1);
|
||||
readSZL(dc,0xD91,0x0);
|
||||
readSZL(dc,0x232,0x4);
|
||||
readSZL(dc,0x1A0,0x0);
|
||||
readSZL(dc,0x0A0,0x0);
|
||||
}
|
||||
|
||||
if(doSZLreadAll) {
|
||||
readSZLAll(dc);
|
||||
}
|
||||
|
||||
if(doStop) {
|
||||
dc.stop();
|
||||
}
|
||||
if(doRun) {
|
||||
dc.start();
|
||||
}
|
||||
if(doBenchmark) {
|
||||
rBenchmark(dc,libnodave.daveFlags);
|
||||
}
|
||||
|
||||
if(doReadout) {
|
||||
loadBlocksOfType(dc, libnodave.daveBlockType_OB, doReadout);
|
||||
loadBlocksOfType(dc, libnodave.daveBlockType_FC, doReadout);
|
||||
loadBlocksOfType(dc, libnodave.daveBlockType_FB, doReadout);
|
||||
loadBlocksOfType(dc, libnodave.daveBlockType_DB, doReadout);
|
||||
loadBlocksOfType(dc, libnodave.daveBlockType_SDB, doReadout);
|
||||
}
|
||||
|
||||
|
||||
if(doNewfunctions) {
|
||||
int saveDebug=libnodave.daveGetDebug();
|
||||
|
||||
Console.WriteLine("Trying to read two consecutive bits from DB11.DBX0.1");;
|
||||
res=dc.readBits(libnodave.daveDB, 11, 1, 2, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read no bit (length 0) from DB17.DBX0.1");
|
||||
res=dc.readBits(libnodave.daveDB, 17, 1, 0, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
libnodave.daveSetDebug(libnodave.daveGetDebug()|libnodave.daveDebugPDU);
|
||||
Console.WriteLine("Trying to read a single bit from DB17.DBX0.3\n");
|
||||
res=dc.readBits(libnodave.daveDB, 17, 3, 1, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read a single bit from E0.2\n");
|
||||
res=dc.readBits(libnodave.daveInputs, 0, 2, 1, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
a=0;
|
||||
Console.WriteLine("Writing 0 to EB0\n");
|
||||
res=dc.writeBytes(libnodave.daveOutputs, 0, 0, 1, BitConverter.GetBytes(libnodave.daveSwapIed_32(a)));
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
a=1;
|
||||
Console.WriteLine("Trying to set single bit E0.5\n");
|
||||
res=dc.writeBits(libnodave.daveOutputs, 0, 5, 1, BitConverter.GetBytes(libnodave.daveSwapIed_32(a)));
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read 1 byte from AAW0\n");
|
||||
res=dc.readBytes(libnodave.daveAnaIn, 0, 0, 2, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
a=2341;
|
||||
Console.WriteLine("Trying to write 1 word (2 bytes) to AAW0\n");
|
||||
res=dc.writeBytes(libnodave.daveAnaOut, 0, 0, 2, BitConverter.GetBytes(libnodave.daveSwapIed_32(a)));
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read 4 items from Timers\n");
|
||||
res=dc.readBytes(libnodave.daveTimer, 0, 0, 4, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
if(res==0) {
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine("Time: %0.3f, ",d);
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine(" %0.3f\n",d);
|
||||
|
||||
d=dc.getSecondsAt(0);
|
||||
Console.WriteLine("Time: %0.3f, ",d);
|
||||
d=dc.getSecondsAt(2);
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSecondsAt(4);
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSecondsAt(6);
|
||||
Console.WriteLine(" %0.3f\n",d);
|
||||
}
|
||||
|
||||
Console.WriteLine("Trying to read 4 items from Counters\n");
|
||||
res=dc.readBytes(libnodave.daveCounter, 0, 0, 4, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
if(res==0) {
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine("Count: %d, ",c);
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine(" %d\n",c);
|
||||
|
||||
c=dc.getCounterValueAt(0);
|
||||
Console.WriteLine("Count: %d, ",c);
|
||||
c=dc.getCounterValueAt(2);
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValueAt(4);
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValueAt(6);
|
||||
Console.WriteLine(" %d\n",c);
|
||||
}
|
||||
|
||||
libnodave.PDU p=dc.prepareReadRequest();
|
||||
p.addVarToReadRequest(libnodave.daveInputs,0,0,1);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveDB,6,20,2);
|
||||
p.addVarToReadRequest(libnodave.daveTimer,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveTimer,0,1,4);
|
||||
p.addVarToReadRequest(libnodave.daveTimer,0,2,4);
|
||||
p.addVarToReadRequest(libnodave.daveCounter,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveCounter,0,1,4);
|
||||
p.addVarToReadRequest(libnodave.daveCounter,0,2,4);
|
||||
libnodave.resultSet rs=new libnodave.resultSet();
|
||||
res=dc.execReadRequest(p, rs);
|
||||
libnodave.daveSetDebug(saveDebug);
|
||||
}
|
||||
|
||||
// System.GarbageCollect();
|
||||
|
||||
if(doMultiple) {
|
||||
Console.WriteLine("Now testing read multiple variables.\n"
|
||||
+"This will read 1 Byte from inputs,\n"
|
||||
+"4 bytes from flags, 2 bytes from DB6,\n"
|
||||
+"and other 2 bytes from flags");
|
||||
wait();
|
||||
libnodave.PDU p=dc.prepareReadRequest();
|
||||
p.addVarToReadRequest(libnodave.daveInputs,0,0,1);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveDB,6,20,2);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,12,2);
|
||||
p.addBitVarToReadRequest(libnodave.daveFlags, 0, 25 /* 25 is 3.1*/, 1);
|
||||
libnodave.resultSet rs=new libnodave.resultSet();
|
||||
res=dc.execReadRequest(p, rs);
|
||||
|
||||
Console.Write("Input Byte 0: ");
|
||||
res=dc.useResult(rs, 0); // first result
|
||||
if (res==0) {
|
||||
a=dc.getU8();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("Flag DWord 0: ");
|
||||
res=dc.useResult(rs, 1); // 2nd result
|
||||
if (res==0) {
|
||||
a=dc.getS16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("DB 6 Word 20: ");
|
||||
res=dc.useResult(rs, 2); // 3rd result
|
||||
if (res==0) {
|
||||
a=dc.getS16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("Flag Word 12: ");
|
||||
res=dc.useResult(rs, 3); // 4th result
|
||||
if (res==0) {
|
||||
a=dc.getU16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("Flag F3.1: ");
|
||||
res=dc.useResult(rs, 4); // 4th result
|
||||
if (res==0) {
|
||||
a=dc.getU8();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("non existing result (we read 5 items, but try to use a 6th one): ");
|
||||
res=dc.useResult(rs, 5); // 5th result
|
||||
if (res==0) {
|
||||
a=dc.getU16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
if (doWrite){
|
||||
Console.WriteLine("Now testing write multiple variables:\n"
|
||||
+"IB0, FW0, QB0, DB6:DBW20 and DB20:DBD24 in a single multiple write.");
|
||||
wait();
|
||||
// libnodave.daveSetDebug(0xffff);
|
||||
byte[] aa={0};
|
||||
libnodave.PDU p2=dc.prepareWriteRequest();
|
||||
p2.addVarToWriteRequest(libnodave.daveInputs,0,0,1, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveFlags,0,4,2, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveOutputs,0,0,2, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveDB,6,20,2, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveDB,20,24,4, aa);
|
||||
aa[0]=1;
|
||||
p2.addBitVarToWriteRequest(libnodave.daveFlags, 0, 27 /* 27 is 3.3*/, 1, aa);
|
||||
rs =new libnodave.resultSet();
|
||||
res=dc.execWriteRequest(p2, rs);
|
||||
Console.WriteLine("Result code for the entire multiple write operation: "+res+"="+libnodave.daveStrerror(res));
|
||||
/*
|
||||
// I could list the single result codes like this, but I want to tell
|
||||
// which item should have been written, so I do it in 5 individual lines:
|
||||
|
||||
for (i=0;i<rs.numResults;i++){
|
||||
res=rs.results[i].error;
|
||||
Console.WriteLine("result code from writing item %d: %d=%s\n",i,res,libnodave.libnodave.daveStrerror(res));
|
||||
}
|
||||
*/
|
||||
int err=rs.getErrorOfResult(0);
|
||||
Console.WriteLine("Result code for writing IB0: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(1);
|
||||
Console.WriteLine("Result code for writing FW4: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(2);
|
||||
Console.WriteLine("Result code for writing QB0: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(3);
|
||||
Console.WriteLine("Result code for writing DB6:DBW20: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(4);
|
||||
Console.WriteLine("Result code for writing DB20:DBD24:"+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(5);
|
||||
Console.WriteLine("Result code for writing F3.3: "+err+"="+libnodave.daveStrerror(err));
|
||||
/*
|
||||
* Read back and show the new values, so users may notice the difference:
|
||||
*/
|
||||
dc.readBytes(libnodave.daveFlags,0,0,16, null);
|
||||
a=dc.getU32();
|
||||
b=dc.getU32();
|
||||
c=dc.getU32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: %d\n",a);
|
||||
Console.WriteLine("FD4: %d\n",b);
|
||||
Console.WriteLine("FD8: %d\n",c);
|
||||
Console.WriteLine("FD12: %f\n",d);
|
||||
} // doWrite
|
||||
}
|
||||
|
||||
dc.disconnectPLC();
|
||||
}
|
||||
di.disconnectAdapter();
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
Console.WriteLine("Here we are");
|
||||
} else {
|
||||
Console.WriteLine("Couldn't open serial port "+args[adrPos]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BIN
Dot.NET/CS/testMPI.exe
Executable file
BIN
Dot.NET/CS/testMPI.exe
Executable file
Binary file not shown.
650
Dot.NET/CS/testS7online.cs
Normal file
650
Dot.NET/CS/testS7online.cs
Normal file
@@ -0,0 +1,650 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
class test {
|
||||
static void wait() {
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
Console.WriteLine("Usage: testS7online [-d] [-w] access point");
|
||||
Console.WriteLine("-w will try to write to Flag words. It will overwrite FB0 to FB15 (MB0 to MB15) !");
|
||||
Console.WriteLine("-d will produce a lot of debug messages.");
|
||||
Console.WriteLine("-b will run benchmarks. Specify -b and -w to run write benchmarks.");
|
||||
Console.WriteLine("-z will read some SZL list items (diagnostic information).");
|
||||
Console.WriteLine("-2 uses a slightly different version of the MPI protocol. Try it, if your Adapter doesn't work.");
|
||||
Console.WriteLine("-m will run a test for multiple variable reads.");
|
||||
Console.WriteLine("-c will write 0 to the PLC memory used in write tests.");
|
||||
Console.WriteLine("-n will test newly added functions.");
|
||||
Console.WriteLine("-a will read out everything from system state lists(SZLs).");
|
||||
Console.WriteLine("-s stops the PLC.");
|
||||
Console.WriteLine("-r tries to put the PLC in run mode.");
|
||||
Console.WriteLine("--readout read program and data blocks from PLC.");
|
||||
Console.WriteLine("--readoutall read all program and data blocks from PLC. Includes SFBs and SFCs.");
|
||||
Console.WriteLine("-<number> will set the speed of MPI/PROFIBUS network to this value (in kBaud). Default is 187. Supported values are 9, 19, 45, 93, 187, 500 and 1500.");
|
||||
Console.WriteLine("--mpi=<number> will use number as the MPI adddres of the PLC. Default is 2.");
|
||||
Console.WriteLine("--mpi2=<number> Use this option to test simultaneous connections to 2 PLCs.");
|
||||
Console.WriteLine(" It will use number as the MPI adddres of the 2nd PLC. Default is no 2nd PLC.");
|
||||
Console.WriteLine(" Most tests are executed with the first PLC. The first read test is also done with");
|
||||
Console.WriteLine(" with the 2nd one to demonstrate that this works.");
|
||||
Console.WriteLine("--local=<number> will set the local MPI adddres to number. Default is 0.");
|
||||
Console.WriteLine("--debug=<number> will set daveDebug to number.");
|
||||
Console.WriteLine("Example: testS7online -w /S7ONLINE");
|
||||
}
|
||||
|
||||
static int initSuccess=0;
|
||||
static int localMPI=0;
|
||||
static int plcMPI=2;
|
||||
static int plc2MPI=-1;
|
||||
static int adrPos=0;
|
||||
static int useProto=libnodave.daveProtoS7online;
|
||||
static int speed=libnodave.daveSpeed187k;
|
||||
static libnodave.daveOSserialType fds;
|
||||
static libnodave.daveInterface di;
|
||||
static libnodave.daveConnection dc;
|
||||
static bool doWrite=false;
|
||||
static bool doClear=false;
|
||||
static bool doRun=false;
|
||||
static bool doStop=false;
|
||||
static bool doWbit=false;
|
||||
static int wbit;
|
||||
static bool doSZLread=false;
|
||||
static bool doSZLreadAll=false;
|
||||
static bool doBenchmark=false;
|
||||
static bool doReadout=false;
|
||||
static bool doSFBandSFC=false;
|
||||
static bool doExperimental=false;
|
||||
static bool doMultiple=false;
|
||||
static bool doNewfunctions=false;
|
||||
|
||||
static void readSZL(libnodave.daveConnection dc, int id, int index) {
|
||||
int res, SZLid, indx, SZcount, SZlen,i,j,len;
|
||||
byte[] ddd=new byte[3000];
|
||||
Console.WriteLine(String.Format("Trying to read SZL-ID {0:X04}, index {1:X02}",id,index));
|
||||
res=dc.readSZL(id,index, ddd,3000);
|
||||
Console.WriteLine("Function result: "+res+" "+libnodave.daveStrerror(res)+" len:"+dc.getAnswLen());
|
||||
|
||||
if (dc.getAnswLen()>=4) {
|
||||
len=dc.getAnswLen()-8;
|
||||
SZLid=libnodave.getU16from(ddd,0);
|
||||
indx=libnodave.getU16from(ddd,2);
|
||||
Console.WriteLine(String.Format("result SZL ID {0:X04}, index {1:X02}",SZLid,indx));
|
||||
int d=8;
|
||||
if (dc.getAnswLen()>=8) {
|
||||
SZlen=libnodave.getU16from(ddd,4);
|
||||
SZcount=libnodave.getU16from(ddd,6);
|
||||
Console.WriteLine(" "+SZcount+" elements of "+SZlen+" bytes");
|
||||
if(len>0){
|
||||
for (i=0;i<SZcount;i++){
|
||||
if(len>0){
|
||||
for (j=0; j<SZlen; j++){
|
||||
if(len>0){
|
||||
Console.Write(String.Format("{0:X02},",ddd[d]));
|
||||
d++;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
Console.WriteLine(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.WriteLine(" ");
|
||||
}
|
||||
|
||||
static void readSZLAll(libnodave.daveConnection dc) {
|
||||
byte[] d=new byte[1000];
|
||||
int res, SZLid, indx, SZcount, SZlen,i,j, rid, rind;
|
||||
|
||||
res=dc.readSZL(0,0, d, 1000);
|
||||
Console.WriteLine(" "+res+" "+dc.getAnswLen());
|
||||
if ((dc.getAnswLen())>=4) {
|
||||
SZLid=dc.getU16();
|
||||
indx=dc.getU16();
|
||||
Console.WriteLine(String.Format("result SZL ID {0:X04} index {1:X02}",SZLid,indx));
|
||||
if ((dc.getAnswLen())>=8) {
|
||||
SZlen=0x100*d[4]+d[5];
|
||||
SZcount=0x100*d[6]+d[7];
|
||||
Console.WriteLine("%d elements of %d bytes\n",SZcount,SZlen);
|
||||
for (i=0;i<SZcount;i++){
|
||||
rid=libnodave.getU16from(d,i*SZlen+8);
|
||||
rind=0;
|
||||
Console.WriteLine(String.Format("\nID:{0:X04} index {1:X02}",rid,rind));
|
||||
readSZL(dc, rid, rind);
|
||||
}
|
||||
}
|
||||
}
|
||||
Console.WriteLine("\n");
|
||||
}
|
||||
|
||||
|
||||
static void rBenchmark(libnodave.daveConnection dc, int bmArea) {
|
||||
int i,res,maxReadLen,areaNumber;
|
||||
double usec;
|
||||
long t1, t2;
|
||||
libnodave.resultSet rs=new libnodave.resultSet();
|
||||
maxReadLen=dc.getMaxPDULen()-46;
|
||||
areaNumber=0;
|
||||
if(bmArea==libnodave.daveDB) areaNumber=1;
|
||||
Console.WriteLine("Now going to do read benchmark with minimum block length of 1.\n");
|
||||
t1=Environment.TickCount;
|
||||
for (i=1;i<101;i++) {
|
||||
dc.readBytes(bmArea, areaNumber,0, 1, null);
|
||||
if (i%10==0) {
|
||||
Console.Write("..."+i);
|
||||
}
|
||||
}
|
||||
t2=Environment.TickCount;
|
||||
usec = 0.001 * (t2 - t1);
|
||||
Console.WriteLine(" 100 reads took "+usec+" secs.");
|
||||
Console.WriteLine("Now going to do read benchmark with shurely supported block length "+maxReadLen);
|
||||
t1=Environment.TickCount;
|
||||
for (i=1;i<101;i++) {
|
||||
dc.readBytes(bmArea, areaNumber, 0, maxReadLen, null);
|
||||
if (i%10==0) {
|
||||
Console.Write("..."+i);
|
||||
}
|
||||
}
|
||||
t2=Environment.TickCount;
|
||||
usec = 0.001 * (t2 - t1);
|
||||
Console.WriteLine(" 100 reads took "+usec+" secs. ");
|
||||
|
||||
Console.WriteLine("Now going to do read benchmark with 5 variables in a single request.");
|
||||
Console.WriteLine("running...");
|
||||
|
||||
t1=Environment.TickCount;
|
||||
|
||||
for (i=1;i<101;i++) {
|
||||
libnodave.PDU p=dc.prepareReadRequest();
|
||||
p.addVarToReadRequest(libnodave.daveInputs,0,0,6);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,0,6);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,6,6);
|
||||
p.addVarToReadRequest(bmArea,areaNumber,4,54);
|
||||
p.addVarToReadRequest(bmArea,areaNumber,4,4);
|
||||
res=dc.execReadRequest(p, rs);
|
||||
if (res!=0) Console.WriteLine("\nerror "+res+" = "+libnodave.daveStrerror(res));
|
||||
if (i%10==0) {
|
||||
Console.Write("..."+i);
|
||||
}
|
||||
}
|
||||
t2=Environment.TickCount;
|
||||
usec = 0.001 * (t2 - t1);
|
||||
Console.WriteLine(" 100 reads took "+usec+" secs.");
|
||||
}
|
||||
|
||||
public static int Main (string[] args)
|
||||
{
|
||||
int i,a=0,j,res,b=0,c=0;
|
||||
float d=0;
|
||||
byte[] buf1=new byte[libnodave.davePartnerListSize];
|
||||
|
||||
if (args.Length <1) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (args[adrPos][0]=='-') {
|
||||
if (args[adrPos].StartsWith("--debug=")) {
|
||||
libnodave.daveSetDebug(Convert.ToInt32(args[adrPos].Substring(8)));
|
||||
Console.WriteLine("setting debug to: ",Convert.ToInt32(args[adrPos].Substring(8)));
|
||||
} else if (args[adrPos].StartsWith("-d")) {
|
||||
libnodave.daveSetDebug(libnodave.daveDebugAll);
|
||||
} else if (args[adrPos].StartsWith("-s")) {
|
||||
doStop=true;
|
||||
} else if (args[adrPos].StartsWith("-w")) {
|
||||
doWrite=true;
|
||||
} else if (args[adrPos].StartsWith("-b")) {
|
||||
doBenchmark=true;
|
||||
} else if (args[adrPos].StartsWith("--readoutall")) {
|
||||
doReadout=true;
|
||||
doSFBandSFC=true;
|
||||
} else if (args[adrPos].StartsWith("--readout")) {
|
||||
doReadout=true;
|
||||
} else if (args[adrPos].StartsWith("-r")) {
|
||||
doRun=true;
|
||||
} else if (args[adrPos].StartsWith("-e")) {
|
||||
doExperimental=true;
|
||||
} else if (args[adrPos].StartsWith("--local=")) {
|
||||
localMPI=Convert.ToInt32(args[adrPos].Substring(8));
|
||||
Console.WriteLine("setting local MPI address to: "+localMPI);
|
||||
} else if (args[adrPos].StartsWith("--mpi=")) {
|
||||
plcMPI=Convert.ToInt32(args[adrPos].Substring(6));
|
||||
Console.WriteLine("setting MPI address of PLC to: "+plcMPI);
|
||||
} else if (args[adrPos].StartsWith("--mpi2=")) {
|
||||
plc2MPI=Convert.ToInt32(args[adrPos].Substring(7));
|
||||
Console.WriteLine("setting MPI address of 2md PLC to: "+plc2MPI);
|
||||
} else if (args[adrPos].StartsWith("--wbit=")) {
|
||||
wbit=Convert.ToInt32(args[adrPos].Substring(7));
|
||||
Console.WriteLine("setting bit number: "+wbit);
|
||||
doWbit=true;
|
||||
} else if (args[adrPos].StartsWith("-z")) {
|
||||
doSZLread=true;
|
||||
} else if (args[adrPos].StartsWith("-a")) {
|
||||
doSZLreadAll=true;
|
||||
} else if (args[adrPos].StartsWith("-m")) {
|
||||
doMultiple=true;
|
||||
} else if (args[adrPos].StartsWith("-c")) {
|
||||
doClear=true;
|
||||
} else if (args[adrPos].StartsWith("-n")) {
|
||||
doNewfunctions=true;
|
||||
} else if (args[adrPos].StartsWith("-9")) {
|
||||
speed=libnodave.daveSpeed9k;
|
||||
} else if (args[adrPos].StartsWith("-19")) {
|
||||
speed=libnodave.daveSpeed19k;
|
||||
} else if (args[adrPos].StartsWith("-45")) {
|
||||
speed=libnodave.daveSpeed45k;
|
||||
} else if (args[adrPos].StartsWith("-93")) {
|
||||
speed=libnodave.daveSpeed93k;
|
||||
} else if (args[adrPos].StartsWith("-500")) {
|
||||
speed=libnodave.daveSpeed500k;
|
||||
} else if (args[adrPos].StartsWith("-1500")) {
|
||||
speed=libnodave.daveSpeed1500k;
|
||||
}
|
||||
|
||||
adrPos++;
|
||||
if (args.Length<=adrPos) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fds.rfd=libnodave.openS7online(args[adrPos]);
|
||||
fds.wfd=fds.rfd;
|
||||
if (fds.rfd>=0) {
|
||||
di =new libnodave.daveInterface(fds, "IF1", localMPI, useProto, speed);
|
||||
di.setTimeout(5000000);
|
||||
for (i=0; i<3; i++) {
|
||||
if (0==di.initAdapter()) {
|
||||
initSuccess=1;
|
||||
a= di.listReachablePartners(buf1);
|
||||
Console.WriteLine("daveListReachablePartners List length: "+a);
|
||||
if (a>0) {
|
||||
for (j=0;j<a;j++) {
|
||||
if (buf1[j]==libnodave.daveMPIReachable)
|
||||
Console.WriteLine("Device at address: "+j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else di.disconnectAdapter();
|
||||
}
|
||||
if (initSuccess==0) {
|
||||
Console.WriteLine("Couldn't connect to Adapter!.\n Please try again. You may also try the option -2 for some adapters.");
|
||||
return -3;
|
||||
}
|
||||
|
||||
dc = new libnodave.daveConnection(di,plcMPI,0,0);
|
||||
|
||||
if (0==dc.connectPLC()) {;
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, null);
|
||||
if (res==0) {
|
||||
a=dc.getS32();
|
||||
b=dc.getS32();
|
||||
c=dc.getS32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: " + a);
|
||||
Console.WriteLine("FD4: " + b);
|
||||
Console.WriteLine("FD8: " + c);
|
||||
Console.WriteLine("FD12: " + d);
|
||||
} else
|
||||
Console.WriteLine("error "+res+" "+libnodave.daveStrerror(res));
|
||||
|
||||
if(doExperimental) {
|
||||
Console.WriteLine("Trying to read outputs");
|
||||
res=dc.readBytes(libnodave.daveOutputs, 0, 0, 2, null);
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
if (res==0) {
|
||||
Console.Write("Bytes:");
|
||||
for (b=0; b<dc.getAnswLen(); b++) {
|
||||
c=dc.getU8();
|
||||
Console.Write(String.Format(" {0:X0}, ",c));
|
||||
}
|
||||
Console.WriteLine("");
|
||||
}
|
||||
a=0x01;
|
||||
Console.WriteLine("Trying to write outputs");
|
||||
res=dc.writeBytes(libnodave.daveOutputs, 0, 0, 1, BitConverter.GetBytes(a));
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
libnodave.daveSetDebug(libnodave.daveDebugAll);
|
||||
res=dc.force200(libnodave.daveOutputs,0,0);
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
libnodave.daveSetDebug(0);
|
||||
res=dc.force200(libnodave.daveOutputs,0,1);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
|
||||
res=dc.force200(libnodave.daveOutputs,0,2);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,0,3);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,1,4);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,2,5);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
res=dc.force200(libnodave.daveOutputs,3,7);
|
||||
Console.WriteLine("function result of force: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
wait();
|
||||
Console.WriteLine("Trying to read outputs again\n");
|
||||
res=dc.readBytes(libnodave.daveOutputs, 0, 0, 4, null);
|
||||
Console.WriteLine("function result: "+res+"="+libnodave.daveStrerror(res)+" "+dc.getAnswLen());
|
||||
if (res==0) {
|
||||
Console.Write("Bytes:");
|
||||
for (b=0; b<dc.getAnswLen(); b++) {
|
||||
c=dc.getU8();
|
||||
Console.Write(String.Format(" {0:X0}, ",c));
|
||||
}
|
||||
Console.WriteLine("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(doWrite) {
|
||||
Console.WriteLine("Now we write back these data after incrementing the integers by 1,2 and 3 and the float by 1.1.\n");
|
||||
wait();
|
||||
/*
|
||||
Attention! you need to daveSwapIed little endian variables before using them as a buffer for
|
||||
daveWriteBytes() or before copying them into a buffer for daveWriteBytes()!
|
||||
*/
|
||||
a=libnodave.daveSwapIed_32(a+1);
|
||||
dc.writeBytes(libnodave.daveFlags,0,0,4,BitConverter.GetBytes(a));
|
||||
b=libnodave.daveSwapIed_32(b+2);
|
||||
dc.writeBytes(libnodave.daveFlags,0,4,4,BitConverter.GetBytes(b));
|
||||
c=libnodave.daveSwapIed_32(c+3);
|
||||
dc.writeBytes(libnodave.daveFlags,0,8,4,BitConverter.GetBytes(c));
|
||||
d=libnodave.toPLCfloat(d+1.1f);
|
||||
dc.writeBytes(libnodave.daveFlags,0,12,4,BitConverter.GetBytes(d));
|
||||
/*
|
||||
* Read back and show the new values, so users may notice the difference:
|
||||
*/
|
||||
dc.readBytes(libnodave.daveFlags,0,0,16, null);
|
||||
a=dc.getU32();
|
||||
b=dc.getU32();
|
||||
c=dc.getU32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: "+a);
|
||||
Console.WriteLine("FD4: "+b);
|
||||
Console.WriteLine("FD8: "+c);
|
||||
Console.WriteLine("FD12: "+d);
|
||||
} // doWrite
|
||||
|
||||
if(doClear) {
|
||||
Console.WriteLine("Now writing 0 to the bytes FB0...FB15.\n");
|
||||
// wait();
|
||||
byte[] aa={0,0,0,0};
|
||||
dc.writeBytes(libnodave.daveFlags,0,0,4,aa);
|
||||
dc.writeBytes(libnodave.daveFlags,0,4,4,aa);
|
||||
dc.writeBytes(libnodave.daveFlags,0,8,4,aa);
|
||||
dc.writeBytes(libnodave.daveFlags,0,12,4,aa);
|
||||
dc.readBytes(libnodave.daveFlags,0,0,16, null);
|
||||
a=dc.getU32();
|
||||
b=dc.getU32();
|
||||
c=dc.getU32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: "+a);
|
||||
Console.WriteLine("FD4: "+b);
|
||||
Console.WriteLine("FD8: "+c);
|
||||
Console.WriteLine("FD12: "+d);
|
||||
} // doClear
|
||||
|
||||
if(doSZLread) {
|
||||
readSZL(dc,0x92,0x0);
|
||||
readSZL(dc,0xB4,0x1024);
|
||||
readSZL(dc,0x111,0x1);
|
||||
readSZL(dc,0xD91,0x0);
|
||||
readSZL(dc,0x232,0x4);
|
||||
readSZL(dc,0x1A0,0x0);
|
||||
readSZL(dc,0x0A0,0x0);
|
||||
}
|
||||
|
||||
if(doSZLreadAll) {
|
||||
readSZLAll(dc);
|
||||
}
|
||||
|
||||
if(doStop) {
|
||||
dc.stop();
|
||||
}
|
||||
if(doRun) {
|
||||
dc.start();
|
||||
}
|
||||
if(doBenchmark) {
|
||||
rBenchmark(dc,libnodave.daveFlags);
|
||||
}
|
||||
|
||||
|
||||
if(doNewfunctions) {
|
||||
int saveDebug=libnodave.daveGetDebug();
|
||||
|
||||
Console.WriteLine("Trying to read two consecutive bits from DB11.DBX0.1");;
|
||||
res=dc.readBits(libnodave.daveDB, 11, 1, 2, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read no bit (length 0) from DB17.DBX0.1");
|
||||
res=dc.readBits(libnodave.daveDB, 17, 1, 0, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
libnodave.daveSetDebug(libnodave.daveGetDebug()|libnodave.daveDebugPDU);
|
||||
Console.WriteLine("Trying to read a single bit from DB17.DBX0.3\n");
|
||||
res=dc.readBits(libnodave.daveDB, 17, 3, 1, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read a single bit from E0.2\n");
|
||||
res=dc.readBits(libnodave.daveInputs, 0, 2, 1, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
a=0;
|
||||
Console.WriteLine("Writing 0 to EB0\n");
|
||||
res=dc.writeBytes(libnodave.daveOutputs, 0, 0, 1, BitConverter.GetBytes(libnodave.daveSwapIed_32(a)));
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
a=1;
|
||||
Console.WriteLine("Trying to set single bit E0.5\n");
|
||||
res=dc.writeBits(libnodave.daveOutputs, 0, 5, 1, BitConverter.GetBytes(libnodave.daveSwapIed_32(a)));
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read 1 byte from AAW0\n");
|
||||
res=dc.readBytes(libnodave.daveAnaIn, 0, 0, 2, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
a=2341;
|
||||
Console.WriteLine("Trying to write 1 word (2 bytes) to AAW0\n");
|
||||
res=dc.writeBytes(libnodave.daveAnaOut, 0, 0, 2, BitConverter.GetBytes(libnodave.daveSwapIed_32(a)));
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
|
||||
Console.WriteLine("Trying to read 4 items from Timers\n");
|
||||
res=dc.readBytes(libnodave.daveTimer, 0, 0, 4, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
if(res==0) {
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine("Time: %0.3f, ",d);
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSeconds();
|
||||
Console.WriteLine(" %0.3f\n",d);
|
||||
|
||||
d=dc.getSecondsAt(0);
|
||||
Console.WriteLine("Time: %0.3f, ",d);
|
||||
d=dc.getSecondsAt(2);
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSecondsAt(4);
|
||||
Console.WriteLine("%0.3f, ",d);
|
||||
d=dc.getSecondsAt(6);
|
||||
Console.WriteLine(" %0.3f\n",d);
|
||||
}
|
||||
|
||||
Console.WriteLine("Trying to read 4 items from Counters\n");
|
||||
res=dc.readBytes(libnodave.daveCounter, 0, 0, 4, null);
|
||||
Console.WriteLine("function result:" + res+ "="+libnodave.daveStrerror(res));
|
||||
if(res==0) {
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine("Count: %d, ",c);
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValue();
|
||||
Console.WriteLine(" %d\n",c);
|
||||
|
||||
c=dc.getCounterValueAt(0);
|
||||
Console.WriteLine("Count: %d, ",c);
|
||||
c=dc.getCounterValueAt(2);
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValueAt(4);
|
||||
Console.WriteLine("%d, ",c);
|
||||
c=dc.getCounterValueAt(6);
|
||||
Console.WriteLine(" %d\n",c);
|
||||
}
|
||||
|
||||
libnodave.PDU p=dc.prepareReadRequest();
|
||||
p.addVarToReadRequest(libnodave.daveInputs,0,0,1);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveDB,6,20,2);
|
||||
p.addVarToReadRequest(libnodave.daveTimer,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveTimer,0,1,4);
|
||||
p.addVarToReadRequest(libnodave.daveTimer,0,2,4);
|
||||
p.addVarToReadRequest(libnodave.daveCounter,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveCounter,0,1,4);
|
||||
p.addVarToReadRequest(libnodave.daveCounter,0,2,4);
|
||||
libnodave.resultSet rs=new libnodave.resultSet();
|
||||
res=dc.execReadRequest(p, rs);
|
||||
libnodave.daveSetDebug(saveDebug);
|
||||
}
|
||||
|
||||
// System.GarbageCollect();
|
||||
|
||||
if(doMultiple) {
|
||||
Console.WriteLine("Now testing read multiple variables.\n"
|
||||
+"This will read 1 Byte from inputs,\n"
|
||||
+"4 bytes from flags, 2 bytes from DB6,\n"
|
||||
+"and other 2 bytes from flags");
|
||||
wait();
|
||||
libnodave.PDU p=dc.prepareReadRequest();
|
||||
p.addVarToReadRequest(libnodave.daveInputs,0,0,1);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,0,4);
|
||||
p.addVarToReadRequest(libnodave.daveDB,6,20,2);
|
||||
p.addVarToReadRequest(libnodave.daveFlags,0,12,2);
|
||||
p.addBitVarToReadRequest(libnodave.daveFlags, 0, 25 /* 25 is 3.1*/, 1);
|
||||
libnodave.resultSet rs=new libnodave.resultSet();
|
||||
res=dc.execReadRequest(p, rs);
|
||||
|
||||
Console.Write("Input Byte 0: ");
|
||||
res=dc.useResult(rs, 0); // first result
|
||||
if (res==0) {
|
||||
a=dc.getU8();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("Flag DWord 0: ");
|
||||
res=dc.useResult(rs, 1); // 2nd result
|
||||
if (res==0) {
|
||||
a=dc.getS16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("DB 6 Word 20: ");
|
||||
res=dc.useResult(rs, 2); // 3rd result
|
||||
if (res==0) {
|
||||
a=dc.getS16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("Flag Word 12: ");
|
||||
res=dc.useResult(rs, 3); // 4th result
|
||||
if (res==0) {
|
||||
a=dc.getU16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("Flag F3.1: ");
|
||||
res=dc.useResult(rs, 4); // 4th result
|
||||
if (res==0) {
|
||||
a=dc.getU8();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
Console.Write("non existing result (we read 5 items, but try to use a 6th one): ");
|
||||
res=dc.useResult(rs, 5); // 5th result
|
||||
if (res==0) {
|
||||
a=dc.getU16();
|
||||
Console.WriteLine(a);
|
||||
} else
|
||||
Console.WriteLine("*** Error: "+libnodave.daveStrerror(res));
|
||||
|
||||
if (doWrite){
|
||||
Console.WriteLine("Now testing write multiple variables:\n"
|
||||
+"IB0, FW0, QB0, DB6:DBW20 and DB20:DBD24 in a single multiple write.");
|
||||
wait();
|
||||
// libnodave.daveSetDebug(0xffff);
|
||||
byte[] aa={0};
|
||||
libnodave.PDU p2=dc.prepareWriteRequest();
|
||||
p2.addVarToWriteRequest(libnodave.daveInputs,0,0,1, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveFlags,0,4,2, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveOutputs,0,0,2, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveDB,6,20,2, aa);
|
||||
p2.addVarToWriteRequest(libnodave.daveDB,20,24,4, aa);
|
||||
aa[0]=1;
|
||||
p2.addBitVarToWriteRequest(libnodave.daveFlags, 0, 27 /* 27 is 3.3*/, 1, aa);
|
||||
rs =new libnodave.resultSet();
|
||||
res=dc.execWriteRequest(p2, rs);
|
||||
Console.WriteLine("Result code for the entire multiple write operation: "+res+"="+libnodave.daveStrerror(res));
|
||||
/*
|
||||
// I could list the single result codes like this, but I want to tell
|
||||
// which item should have been written, so I do it in 5 individual lines:
|
||||
|
||||
for (i=0;i<rs.numResults;i++){
|
||||
res=rs.results[i].error;
|
||||
Console.WriteLine("result code from writing item %d: %d=%s\n",i,res,libnodave.libnodave.daveStrerror(res));
|
||||
}
|
||||
*/
|
||||
int err=rs.getErrorOfResult(0);
|
||||
Console.WriteLine("Result code for writing IB0: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(1);
|
||||
Console.WriteLine("Result code for writing FW4: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(2);
|
||||
Console.WriteLine("Result code for writing QB0: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(3);
|
||||
Console.WriteLine("Result code for writing DB6:DBW20: "+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(4);
|
||||
Console.WriteLine("Result code for writing DB20:DBD24:"+err+"="+libnodave.daveStrerror(err));
|
||||
err=rs.getErrorOfResult(5);
|
||||
Console.WriteLine("Result code for writing F3.3: "+err+"="+libnodave.daveStrerror(err));
|
||||
/*
|
||||
* Read back and show the new values, so users may notice the difference:
|
||||
*/
|
||||
dc.readBytes(libnodave.daveFlags,0,0,16, null);
|
||||
a=dc.getU32();
|
||||
b=dc.getU32();
|
||||
c=dc.getU32();
|
||||
d=dc.getFloat();
|
||||
Console.WriteLine("FD0: %d\n",a);
|
||||
Console.WriteLine("FD4: %d\n",b);
|
||||
Console.WriteLine("FD8: %d\n",c);
|
||||
Console.WriteLine("FD12: %f\n",d);
|
||||
} // doWrite
|
||||
}
|
||||
|
||||
dc.disconnectPLC();
|
||||
}
|
||||
di.disconnectAdapter();
|
||||
libnodave.closeS7online(fds.rfd);
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
|
||||
Console.WriteLine("Here we are");
|
||||
} else {
|
||||
Console.WriteLine("Couldn't open s7 online "+args[adrPos]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BIN
Dot.NET/CS/testS7online.exe
Executable file
BIN
Dot.NET/CS/testS7online.exe
Executable file
Binary file not shown.
5
Dot.NET/MSnet.bat
Executable file
5
Dot.NET/MSnet.bat
Executable file
@@ -0,0 +1,5 @@
|
||||
csc /t:library libnodave.net.cs
|
||||
vbc /r:libnodave.net.dll VB/simpleMPI.vb
|
||||
csc /r:libnodave.net CS/testMPI.cs
|
||||
csc /r:libnodave.net CS/testS7online.cs
|
||||
|
||||
6
Dot.NET/VB/readme
Executable file
6
Dot.NET/VB/readme
Executable file
@@ -0,0 +1,6 @@
|
||||
The test programs for VB.Net are far less complete than those for C#. The reason is that I compile
|
||||
and test under MONO, a free .Net clone. MONO's Basic compiler is in an early stage and if I add
|
||||
some more lines, it doesn't work any more.
|
||||
If you have #Develop: A user reported that you can put a CSharp program into #Develop and have it
|
||||
converted to VB without any problem or even manual work.
|
||||
|
||||
80
Dot.NET/VB/simpleMPI.vb
Executable file
80
Dot.NET/VB/simpleMPI.vb
Executable file
@@ -0,0 +1,80 @@
|
||||
'
|
||||
' Very simple program to read from a 300/400 PLC via MPI adapter.
|
||||
' This shall provide users wit a simple starting point for their own
|
||||
' applications.
|
||||
'
|
||||
' Part of Libnodave, a free communication libray for Siemens S7 200/300/400
|
||||
'
|
||||
' (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005
|
||||
'
|
||||
' Libnodave is free software; you can redistribute it and/or modify
|
||||
' it under the terms of the GNU Library General Public License as published by
|
||||
' the Free Software Foundation; either version 2, or (at your option)
|
||||
' any later version.
|
||||
'
|
||||
' Libnodave is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
' GNU General Public License for more details.
|
||||
'
|
||||
' You should have received a copy of the GNU Library General Public License
|
||||
' along with Libnodave; see the file COPYING. If not, write to
|
||||
' the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
'
|
||||
|
||||
Imports System
|
||||
Imports Microsoft.VisualBasic
|
||||
|
||||
Class test
|
||||
Public Shared Function Main(args() As String) As Integer
|
||||
|
||||
Dim localMPI As Integer = 0, plcMPI As Integer = 2
|
||||
|
||||
Dim fds As libnodave.daveOSserialType
|
||||
Dim di as libnodave.daveInterface
|
||||
Dim dc as libnodave.daveConnection
|
||||
Dim res As Integer
|
||||
Dim a,b,c As Integer, d As Single
|
||||
Dim buf(1000) as byte
|
||||
Dim s As string
|
||||
|
||||
Console.WriteLine("Hello World!")
|
||||
fds.rfd=libnodave.setPort(args(0), "38400", AscW("O")) ' step 1, open a connection
|
||||
fds.wfd=fds.rfd
|
||||
if fds.rfd>0 then ' if step 1 is ok
|
||||
di =new libnodave.daveInterface(fds, "My Interface 1", localMPI, libnodave.daveProtoMPI, libnodave.daveSpeed187k)
|
||||
di.setTimeout(1000000) ' Make this longer if you have a very long response time
|
||||
res = di.initAdapter
|
||||
'
|
||||
if res=0 then ' init Adapter is ok
|
||||
dc = new libnodave.daveConnection(di, plcMPI, 0, 0) ' rack amd slot don't matter in case of MPI
|
||||
res=dc.connectPLC()
|
||||
if res=0 then
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, buf)
|
||||
if res=0 then
|
||||
a=dc.getS32
|
||||
b=dc.getS32
|
||||
c=dc.getS32
|
||||
d=dc.getFloat
|
||||
Console.WriteLine("FD0: {0:d}", a)
|
||||
Console.WriteLine("FD4: {0:d}", b)
|
||||
Console.WriteLine("FD8: {0:d}", c)
|
||||
Console.WriteLine("FD12: {0:f}", d)
|
||||
else
|
||||
Console.WriteLine("Error {0:d}={1:s} in readBytes.", res, libnodave.daveStrerror(res))
|
||||
end if
|
||||
dc.disconnectPLC()
|
||||
else
|
||||
Console.WriteLine("Error {0:d}={1:s} in connectPLC.", res, libnodave.daveStrerror(res))
|
||||
end if
|
||||
di.disconnectAdapter() ' End connection to adapter
|
||||
else
|
||||
Console.WriteLine("Error {0:d}={1:s} in initAdapter.", res, libnodave.daveStrerror(res))
|
||||
end if
|
||||
libnodave.closePort(fds.rfd) ' Clean up
|
||||
else
|
||||
Console.WriteLine("Couldn't open serial port {0:s}", args(0))
|
||||
return -1
|
||||
end if 'fds.rfd >0
|
||||
end Function 'Main
|
||||
END class
|
||||
BIN
Dot.NET/VB/simpleMPI2.exe
Executable file
BIN
Dot.NET/VB/simpleMPI2.exe
Executable file
Binary file not shown.
90
Dot.NET/VB/simpleMPI2.vb
Executable file
90
Dot.NET/VB/simpleMPI2.vb
Executable file
@@ -0,0 +1,90 @@
|
||||
'
|
||||
' Very simple program to read from a 300/400 PLC via MPI adapter.
|
||||
' This shall provide users wit a simple starting point for their own
|
||||
' applications.
|
||||
'
|
||||
' Part of Libnodave, a free communication libray for Siemens S7 200/300/400
|
||||
'
|
||||
' (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005
|
||||
'
|
||||
' Libnodave is free software; you can redistribute it and/or modify
|
||||
' it under the terms of the GNU Library General Public License as published by
|
||||
' the Free Software Foundation; either version 2, or (at your option)
|
||||
' any later version.
|
||||
'
|
||||
' Libnodave is distributed in the hope that it will be useful,
|
||||
' but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
' GNU General Public License for more details.
|
||||
'
|
||||
' You should have received a copy of the GNU Library General Public License
|
||||
' along with Libnodave; see the file COPYING. If not, write to
|
||||
' the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
'
|
||||
|
||||
Imports System
|
||||
Imports Microsoft.VisualBasic
|
||||
|
||||
Class test
|
||||
Public Shared Function Main(args() As String) As Integer
|
||||
|
||||
Dim localMPI As Integer = 0, plcMPI As Integer = 2
|
||||
|
||||
Dim fds As libnodave.daveOSserialType
|
||||
Dim di as libnodave.daveInterface
|
||||
Dim dc as libnodave.daveConnection
|
||||
Dim res As Integer
|
||||
Dim a,b,c As Integer, d As Single
|
||||
Dim buf(1000) as byte
|
||||
Dim s As string
|
||||
|
||||
Console.WriteLine("Hello World!")
|
||||
fds.rfd=libnodave.setPort(args(0), "38400", AscW("O")) ' step 1, open a connection
|
||||
fds.wfd=fds.rfd
|
||||
if fds.rfd>0 then ' if step 1 is ok
|
||||
di =new libnodave.daveInterface(fds, "My Interface 1", localMPI, libnodave.daveProtoMPI, libnodave.daveSpeed187k)
|
||||
di.setTimeout(1000000) ' Make this longer if you have a very long response time
|
||||
res = di.initAdapter
|
||||
'
|
||||
if res=0 then ' init Adapter is ok
|
||||
dc = new libnodave.daveConnection(di, plcMPI, 0, 0) ' rack amd slot don't matter in case of MPI
|
||||
res=dc.connectPLC()
|
||||
if res=0 then
|
||||
res=dc.readBytes(libnodave.daveFlags, 0, 0, 16, buf)
|
||||
if res=0 then
|
||||
a=dc.getS32
|
||||
b=dc.getS32
|
||||
c=dc.getS32
|
||||
d=dc.getFloat
|
||||
Console.WriteLine("FD0: {0:d}", a)
|
||||
Console.WriteLine("FD4: {0:d}", b)
|
||||
Console.WriteLine("FD8: {0:d}", c)
|
||||
Console.WriteLine("FD12: {0:f}", d)
|
||||
else
|
||||
s=libnodave.daveStrerror(res)
|
||||
' Console.WriteLine("Error {0:d}={1:s} in readBytes.", res, libnodave.daveStrerror(res))
|
||||
Console.Write("Error {0:d} in readBytes.", res)
|
||||
Console.WriteLine(s)
|
||||
end if
|
||||
dc.disconnectPLC()
|
||||
else
|
||||
s=libnodave.daveStrerror(res)
|
||||
' Console.WriteLine("Error {0:d}={1:s} in connectPLC.", res, libnodave.daveStrerror(res))
|
||||
Console.Write("Error {0:d} in connectPLC.", res)
|
||||
Console.WriteLine(s)
|
||||
end if
|
||||
di.disconnectAdapter() ' End connection to adapter
|
||||
else
|
||||
s=libnodave.daveStrerror(res)
|
||||
' Console.WriteLine("Error {0:d}={1:s} in initAdapter.", res, libnodave.daveStrerror(res))
|
||||
' Console.WriteLine("Error {0:d}={1:s} in initAdapter.", res, s)
|
||||
Console.Write("Error {0:d} in initAdapter.", res)
|
||||
Console.WriteLine(s)
|
||||
end if
|
||||
libnodave.closePort(fds.rfd) ' Clean up
|
||||
else
|
||||
Console.WriteLine("Couldn't open serial port {0:s}", args(0))
|
||||
return -1
|
||||
end if 'fds.rfd >0
|
||||
end Function 'Main
|
||||
END class
|
||||
815
Dot.NET/libnodave.net.cs
Normal file
815
Dot.NET/libnodave.net.cs
Normal file
@@ -0,0 +1,815 @@
|
||||
/*
|
||||
This implements a "glue" layer between libnodave.dll and applications written
|
||||
in MS .Net languages.
|
||||
|
||||
Part of Libnodave, a free communication libray for Siemens S7 200/300/400 via
|
||||
the MPI adapter 6ES7 972-0CA22-0XAC
|
||||
or MPI adapter 6ES7 972-0CA23-0XAC
|
||||
or TS adapter 6ES7 972-0CA33-0XAC
|
||||
or MPI adapter 6ES7 972-0CA11-0XAC,
|
||||
IBH/MHJ-NetLink or CPs 243, 343 and 443
|
||||
or VIPA Speed7 with builtin ethernet support.
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2002..2005
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with Libnodave; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class libnodave {
|
||||
/*
|
||||
This struct contains whatever your Operating System uses to hold an in and outgoing
|
||||
connection to external devices.
|
||||
*/
|
||||
public struct daveOSserialType {
|
||||
public int rfd;
|
||||
public int wfd;
|
||||
}
|
||||
/*
|
||||
Protocol types to be used with new daveInterface:
|
||||
*/
|
||||
public static readonly int daveProtoMPI=0; /* MPI for S7 300/400 */
|
||||
public static readonly int daveProtoMPI2 = 1; /* MPI for S7 300/400, "Andrew's version" */
|
||||
public static readonly int daveProtoMPI3 = 2; /* MPI for S7 300/400, Step 7 Version, experimental */
|
||||
public static readonly int daveProtoMPI4 = 3; /* MPI for S7 300/400, "Andrew's version" with STX */
|
||||
public static readonly int daveProtoPPI = 10; /* PPI for S7 200 */
|
||||
|
||||
public static readonly int daveProtoAS511 = 20; /* S5 via programming interface */
|
||||
public static readonly int daveProtoS7online = 50; /* use s7onlinx.dll for transport */
|
||||
|
||||
public static readonly int daveProtoISOTCP = 122; /* ISO over TCP */
|
||||
public static readonly int daveProtoISOTCP243 = 123; /* ISO over TCP with CP243 */
|
||||
|
||||
public static readonly int daveProtoMPI_IBH = 223; /* MPI with IBH NetLink MPI to ethernet gateway */
|
||||
public static readonly int daveProtoPPI_IBH = 224; /* PPI with IBH NetLink PPI to ethernet gateway */
|
||||
|
||||
public static readonly int daveProtoUserTransport = 255; /* Libnodave will pass the PDUs of */
|
||||
/* S7 Communication to user defined */
|
||||
/* call back functions. */
|
||||
/*
|
||||
* ProfiBus speed constants. This is the baudrate on MPI network, NOT between adapter and PC:
|
||||
*/
|
||||
public static readonly int daveSpeed9k = 0;
|
||||
public static readonly int daveSpeed19k = 1;
|
||||
public static readonly int daveSpeed187k = 2;
|
||||
public static readonly int daveSpeed500k = 3;
|
||||
public static readonly int daveSpeed1500k = 4;
|
||||
public static readonly int daveSpeed45k = 5;
|
||||
public static readonly int daveSpeed93k = 6;
|
||||
|
||||
/*
|
||||
Some function codes (yet unused ones may be incorrect).
|
||||
*/
|
||||
public static readonly int daveFuncOpenS7Connection = 0xF0;
|
||||
public static readonly int daveFuncRead = 0x04;
|
||||
public static readonly int daveFuncWrite = 0x05;
|
||||
public static readonly int daveFuncRequestDownload = 0x1A;
|
||||
public static readonly int daveFuncDownloadBlock = 0x1B;
|
||||
public static readonly int daveFuncDownloadEnded = 0x1C;
|
||||
public static readonly int daveFuncStartUpload = 0x1D;
|
||||
public static readonly int daveFuncUpload = 0x1E;
|
||||
public static readonly int daveFuncEndUpload = 0x1F;
|
||||
public static readonly int daveFuncInsertBlock = 0x28;
|
||||
/*
|
||||
S7 specific constants:
|
||||
*/
|
||||
public static readonly int daveBlockType_OB = '8';
|
||||
public static readonly int daveBlockType_DB = 'A';
|
||||
public static readonly int daveBlockType_SDB = 'B';
|
||||
public static readonly int daveBlockType_FC = 'C';
|
||||
public static readonly int daveBlockType_SFC = 'D';
|
||||
public static readonly int daveBlockType_FB = 'E';
|
||||
public static readonly int daveBlockType_SFB = 'F';
|
||||
/*
|
||||
Use these constants for parameter "area" in daveReadBytes and daveWriteBytes
|
||||
*/
|
||||
public static readonly int daveSysInfo = 0x3; /* System info of 200 family */
|
||||
public static readonly int daveSysFlags = 0x5; /* System flags of 200 family */
|
||||
public static readonly int daveAnaIn = 0x6; /* analog inputs of 200 family */
|
||||
public static readonly int daveAnaOut = 0x7; /* analog outputs of 200 family */
|
||||
public static readonly int daveP = 0x80; /* direct peripheral access */
|
||||
public static readonly int daveInputs = 0x81;
|
||||
public static readonly int daveOutputs = 0x82;
|
||||
public static readonly int daveFlags = 0x83;
|
||||
public static readonly int daveDB = 0x84; /* data blocks */
|
||||
public static readonly int daveDI = 0x85; /* instance data blocks */
|
||||
public static readonly int daveLocal = 0x86; /* not tested */
|
||||
public static readonly int daveV = 0x87; /* don't know what it is */
|
||||
public static readonly int daveCounter = 28; /* S7 counters */
|
||||
public static readonly int daveTimer = 29; /* S7 timers */
|
||||
public static readonly int daveCounter200 = 30; /* IEC counters (200 family) */
|
||||
public static readonly int daveTimer200 = 31; /* IEC timers (200 family) */
|
||||
/**
|
||||
Library specific:
|
||||
**/
|
||||
/*
|
||||
Result codes. Genarally, 0 means ok,
|
||||
>0 are results (also errors) reported by the PLC
|
||||
<0 means error reported by library code.
|
||||
*/
|
||||
public static readonly int daveResOK = 0; /* means all ok */
|
||||
public static readonly int daveResNoPeripheralAtAddress = 1; /* CPU tells there is no peripheral at address */
|
||||
public static readonly int daveResMultipleBitsNotSupported = 6; /* CPU tells it does not support to read a bit block with a */
|
||||
/* length other than 1 bit. */
|
||||
public static readonly int daveResItemNotAvailable200 = 3; /* means a a piece of data is not available in the CPU, e.g. */
|
||||
/* when trying to read a non existing DB or bit bloc of length<>1 */
|
||||
/* This code seems to be specific to 200 family. */
|
||||
|
||||
public static readonly int daveResItemNotAvailable = 10; /* means a a piece of data is not available in the CPU, e.g. */
|
||||
/* when trying to read a non existing DB */
|
||||
|
||||
public static readonly int daveAddressOutOfRange = 5; /* means the data address is beyond the CPUs address range */
|
||||
public static readonly int daveWriteDataSizeMismatch = 7; /* means the write data size doesn't fit item size */
|
||||
public static readonly int daveResCannotEvaluatePDU = -123; /* PDU is not understood by libnodave */
|
||||
public static readonly int daveResCPUNoData = -124;
|
||||
public static readonly int daveUnknownError = -125;
|
||||
public static readonly int daveEmptyResultError = -126;
|
||||
public static readonly int daveEmptyResultSetError = -127;
|
||||
public static readonly int daveResUnexpectedFunc = -128;
|
||||
public static readonly int daveResUnknownDataUnitSize = -129;
|
||||
|
||||
public static readonly int daveResShortPacket = -1024;
|
||||
public static readonly int daveResTimeout = -1025;
|
||||
/*
|
||||
Error code to message string conversion:
|
||||
Call this function to get an explanation for error codes returned by other functions.
|
||||
*/
|
||||
/*
|
||||
[DllImport("libnodave.dll")]
|
||||
public static extern string
|
||||
daveStrerror(int res);
|
||||
*/
|
||||
[DllImport("libnodave.dll", EntryPoint="daveStrerror" )]
|
||||
public static extern IntPtr
|
||||
_daveStrerror(int res);
|
||||
public static string daveStrerror(int res) {
|
||||
// return Marshal.PtrToStringAuto(_daveStrerror(res));
|
||||
return Marshal.PtrToStringAnsi(_daveStrerror(res)); //hope this fixes bug with intzerpreting string as unicode. Thanks to Luca Domenichini
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Copy an internal String into an external string buffer. This is needed to interface
|
||||
with Visual Basic. Maybe it is helpful elsewhere, too.
|
||||
C# can well work with C strings.
|
||||
*/
|
||||
//EXPORTSPEC void DECL2 daveStringCopy(char * intString, char * extString);
|
||||
|
||||
/*
|
||||
Max number of bytes in a single message.
|
||||
*/
|
||||
public static readonly int daveMaxRawLen = 2048;
|
||||
|
||||
/*
|
||||
Some definitions for debugging:
|
||||
*/
|
||||
public static readonly int daveDebugRawRead = 0x01; /* Show the single bytes received */
|
||||
public static readonly int daveDebugSpecialChars = 0x02; /* Show when special chars are read */
|
||||
public static readonly int daveDebugRawWrite = 0x04; /* Show the single bytes written */
|
||||
public static readonly int daveDebugListReachables = 0x08; /* Show the steps when determine devices in MPI net */
|
||||
public static readonly int daveDebugInitAdapter = 0x10; /* Show the steps when Initilizing the MPI adapter */
|
||||
public static readonly int daveDebugConnect = 0x20; /* Show the steps when connecting a PLC */
|
||||
public static readonly int daveDebugPacket = 0x40;
|
||||
public static readonly int daveDebugByte = 0x80;
|
||||
public static readonly int daveDebugCompare = 0x100;
|
||||
public static readonly int daveDebugExchange = 0x200;
|
||||
public static readonly int daveDebugPDU = 0x400; /* debug PDU handling */
|
||||
public static readonly int daveDebugUpload = 0x800; /* debug PDU loading program blocks from PLC */
|
||||
public static readonly int daveDebugMPI = 0x1000;
|
||||
public static readonly int daveDebugPrintErrors = 0x2000; /* Print error messages */
|
||||
public static readonly int daveDebugPassive = 0x4000;
|
||||
|
||||
public static readonly int daveDebugErrorReporting = 0x8000;
|
||||
public static readonly int daveDebugOpen = 0x10000;
|
||||
|
||||
public static readonly int daveDebugAll = 0x1ffff;
|
||||
/*
|
||||
set and read debug level:
|
||||
*/
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern void daveSetDebug(int newDebugLevel);
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern int daveGetDebug();
|
||||
|
||||
public static int daveMPIReachable = 0x30;
|
||||
public static int daveMPIunused = 0x10;
|
||||
public static int davePartnerListSize = 126;
|
||||
|
||||
/*
|
||||
This wrapper class is used to avoid dealing with "unsafe" pointers to libnodave
|
||||
internal structures. More wrapper classes are derived from this for the different
|
||||
structures. Constructors of derived classes will call functions in libnodave that
|
||||
allocate internal structures via malloc. The functions used return integers by
|
||||
declaration. These integers are stored in "pointer" In fact, these integers contain
|
||||
the "bit patterns" of the pointers. The compiler is deceived about the real nature of
|
||||
the return values. This is ok as long as the pointers are only used in libnodave,
|
||||
because libnodave routines are assumed to know what they may do with them.
|
||||
The destructor here passes the pointers back to libnodave's daveFree to release memory
|
||||
when the C# object is destructed.
|
||||
*/
|
||||
public class pseudoPointer {
|
||||
public IntPtr pointer;
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false*/)]
|
||||
protected static extern int daveFree(IntPtr p);
|
||||
|
||||
~pseudoPointer(){
|
||||
// Console.WriteLine("~pseudoPointer()"+pointer);
|
||||
daveFree(pointer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class daveInterface: pseudoPointer {
|
||||
|
||||
// [DllImport("libnodave.dll"//, PreserveSig=false)]
|
||||
/*
|
||||
I cannot say why, but when I recompiled the existing code with latest libnodave.dll
|
||||
(after using stdcall so that VC++ producs these "decorated names", I got a runtime
|
||||
error about not finding daveNewInterface. When I state full name entry point explicitly,
|
||||
(like below) it runs. The most strange thing is that all other functions work well...
|
||||
*/
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
|
||||
static extern IntPtr daveNewInterface(
|
||||
daveOSserialType fd,
|
||||
string name,
|
||||
int localMPI,
|
||||
int useProto,
|
||||
int speed
|
||||
);
|
||||
public daveInterface(daveOSserialType fd,
|
||||
string name,
|
||||
int localMPI,
|
||||
int useProto,
|
||||
int speed) {
|
||||
pointer=daveNewInterface(fd, name, localMPI, useProto, speed);
|
||||
}
|
||||
|
||||
/*
|
||||
This was just here to check inheritance
|
||||
~daveInterface(){
|
||||
Console.WriteLine("destructor("+daveGetName(pointer)+")");
|
||||
Console.WriteLine("~daveInterface()"+pointer);
|
||||
daveFree(pointer);
|
||||
}
|
||||
*/
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveInitAdapter(IntPtr di);
|
||||
public int initAdapter() {
|
||||
return daveInitAdapter(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveListReachablePartners(IntPtr di, byte[] buffer);
|
||||
public int listReachablePartners(byte[] buffer) {
|
||||
return daveListReachablePartners(pointer,buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern void daveSetTimeout(IntPtr di, int time);
|
||||
public void setTimeout(int time) {
|
||||
daveSetTimeout(pointer, time);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetTimeout(IntPtr di);
|
||||
public int getTimeout() {
|
||||
return daveGetTimeout(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern IntPtr daveDisconnectAdapter(IntPtr di);
|
||||
public IntPtr disconnectAdapter() {
|
||||
return daveDisconnectAdapter(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern string daveGetName(IntPtr di);
|
||||
public string getName() {
|
||||
return daveGetName(pointer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class daveConnection:pseudoPointer {
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern IntPtr daveNewConnection(
|
||||
IntPtr di,
|
||||
int MPI,
|
||||
int rack,
|
||||
int slot
|
||||
);
|
||||
public daveConnection(
|
||||
daveInterface di,
|
||||
int MPI,
|
||||
int rack,
|
||||
int slot
|
||||
) {
|
||||
pointer=daveNewConnection(
|
||||
di.pointer, MPI, rack, slot
|
||||
);
|
||||
}
|
||||
/* This wa here to test inheritance
|
||||
~daveConnection(){
|
||||
Console.WriteLine("~daveConnection()"+pointer);
|
||||
daveFree(pointer);
|
||||
daveFree(pointer);
|
||||
}
|
||||
*/
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveConnectPLC(IntPtr dc);
|
||||
public int connectPLC(){
|
||||
return daveConnectPLC(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveDisconnectPLC(IntPtr dc);
|
||||
public int disconnectPLC() {
|
||||
return daveDisconnectPLC(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveReadBytes(IntPtr dc, int area, int DBnumber, int start, int len, byte[] buffer);
|
||||
public int readBytes(int area, int DBnumber, int start, int len, byte[] buffer) {
|
||||
return daveReadBytes(pointer, area, DBnumber, start, len, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveReadManyBytes(IntPtr dc, int area, int DBnumber, int start, int len, byte[] buffer);
|
||||
public int readManyBytes(int area, int DBnumber, int start, int len, byte[] buffer) {
|
||||
return daveReadManyBytes(pointer, area, DBnumber, start, len, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveReadBits(IntPtr dc, int area, int DBnumber, int start, int len, byte[] buffer);
|
||||
public int readBits(int area, int DBnumber, int start, int len, byte[] buffer) {
|
||||
return daveReadBits(pointer, area, DBnumber, start, len, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveWriteBytes(IntPtr dc, int area, int DBnumber, int start, int len, byte[] buffer);
|
||||
public int writeBytes(int area, int DBnumber, int start, int len, byte[] buffer) {
|
||||
return daveWriteBytes(pointer, area, DBnumber, start, len, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveWriteManyBytes(IntPtr dc, int area, int DBnumber, int start, int len, byte[] buffer);
|
||||
public int writeManyBytes(int area, int DBnumber, int start, int len, byte[] buffer) {
|
||||
return daveWriteManyBytes(pointer, area, DBnumber, start, len, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveWriteBits(IntPtr dc, int area, int DBnumber, int start, int len, byte[] buffer);
|
||||
public int writeBits(int area, int DBnumber, int start, int len, byte[] buffer) {
|
||||
return daveWriteBits(pointer, area, DBnumber, start, len, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetS32(IntPtr dc);
|
||||
public int getS32() {
|
||||
return daveGetS32(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetU32(IntPtr dc);
|
||||
public int getU32() {
|
||||
return daveGetU32(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetS16(IntPtr dc);
|
||||
public int getS16() {
|
||||
return daveGetS16(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetU16(IntPtr dc);
|
||||
public int getU16() {
|
||||
return daveGetU16(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetS8(IntPtr dc);
|
||||
public int getS8() {
|
||||
return daveGetS8(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetU8(IntPtr dc);
|
||||
public int getU8() {
|
||||
return daveGetU8(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern float daveGetFloat(IntPtr dc);
|
||||
public float getFloat() {
|
||||
return daveGetFloat(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetCounterValue(IntPtr dc);
|
||||
public int getCounterValue() {
|
||||
return daveGetCounterValue(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern float daveGetSeconds(IntPtr dc);
|
||||
public float getSeconds() {
|
||||
return daveGetSeconds(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetS32At(IntPtr dc,int pos);
|
||||
public int getS32At(int pos) {
|
||||
return daveGetS32At(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetU32At(IntPtr dc, int pos);
|
||||
public int getU32At(int pos) {
|
||||
return daveGetU32At(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetS16At(IntPtr dc, int pos);
|
||||
public int getS16At(int pos) {
|
||||
return daveGetS16At(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetU16At(IntPtr dc, int pos);
|
||||
public int getU16At(int pos) {
|
||||
return daveGetU16At(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetS8At(IntPtr dc, int pos);
|
||||
public int getS8At(int pos) {
|
||||
return daveGetS8At(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetU8At(IntPtr dc, int pos);
|
||||
public int getU8At(int pos) {
|
||||
return daveGetU8At(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern float daveGetFloatAt(IntPtr dc, int pos);
|
||||
public float getFloatAt(int pos) {
|
||||
return daveGetFloatAt(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetCounterValueAt(IntPtr dc, int pos);
|
||||
public int getCounterValueAt(int pos) {
|
||||
return daveGetCounterValueAt(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern float daveGetSecondsAt(IntPtr dc, int pos);
|
||||
public float getSecondsAt(int pos) {
|
||||
return daveGetSecondsAt(pointer, pos);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetAnswLen(IntPtr dc);
|
||||
public int getAnswLen() {
|
||||
return daveGetAnswLen(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetMaxPDULen(IntPtr dc);
|
||||
public int getMaxPDULen() {
|
||||
return daveGetMaxPDULen(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int davePrepareReadRequest(IntPtr dc, IntPtr p);
|
||||
public PDU prepareReadRequest() {
|
||||
PDU p=new PDU();
|
||||
davePrepareReadRequest(pointer, p.pointer);
|
||||
return p;
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int davePrepareWriteRequest(IntPtr dc, IntPtr p);
|
||||
public PDU prepareWriteRequest() {
|
||||
PDU p=new PDU();
|
||||
davePrepareWriteRequest(pointer, p.pointer);
|
||||
return p;
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveExecReadRequest(IntPtr dc, IntPtr p, IntPtr rl);
|
||||
public int execReadRequest(PDU p, resultSet rl) {
|
||||
return daveExecReadRequest(pointer, p.pointer, rl.pointer);
|
||||
}
|
||||
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveExecWriteRequest(IntPtr dc, IntPtr p, IntPtr rl);
|
||||
public int execWriteRequest(PDU p, resultSet rl) {
|
||||
return daveExecWriteRequest(pointer, p.pointer, rl.pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveUseResult(IntPtr dc, IntPtr rs, int number);
|
||||
public int useResult(resultSet rs, int number) {
|
||||
return daveUseResult(pointer, rs.pointer, number);
|
||||
}
|
||||
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveReadSZL(IntPtr dc,int id,int index,byte[] ddd, int len);
|
||||
public int readSZL(int id,int index,byte[] ddd, int len) {
|
||||
return daveReadSZL(pointer,id,index, ddd, len);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveStart(IntPtr dc);
|
||||
public int start() {
|
||||
return daveStart(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveStop(IntPtr dc);
|
||||
public int stop() {
|
||||
return daveStop(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveForce200(IntPtr dc, int area, int start, int val);
|
||||
public int force200(int area, int start, int val) {
|
||||
return daveForce200(pointer, area, start, val);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveForceDisconnectIBH(IntPtr dc, int src, int dest, int MPI);
|
||||
public int forceDisconnectIBH(int src, int dest, int MPI) {
|
||||
return daveForceDisconnectIBH(pointer, src, dest, MPI);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetResponse(IntPtr dc);
|
||||
public int getGetResponse() {
|
||||
return daveGetResponse(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveSendMessage(IntPtr dc, IntPtr p);
|
||||
public int getMessage(PDU p) {
|
||||
return daveSendMessage(pointer, p.pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll")]
|
||||
protected static extern int daveGetProgramBlock(IntPtr dc, int blockType, int number, byte[] buffer, ref int length);
|
||||
public int getProgramBlock(int blockType, int number, byte[] buffer, ref int length) {
|
||||
Console.WriteLine("length:"+length);
|
||||
int a=daveGetProgramBlock(pointer, blockType, number, buffer, ref length);
|
||||
Console.WriteLine("length:"+length);
|
||||
return a;
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll")]
|
||||
protected static extern int daveListBlocksOfType(IntPtr dc, int blockType, byte[] buffer);
|
||||
public int ListBlocksOfType(int blockType, byte[] buffer) {
|
||||
return daveListBlocksOfType(pointer, blockType, buffer);
|
||||
// return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class PDU:pseudoPointer {
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern IntPtr daveNewPDU();
|
||||
|
||||
public PDU() {
|
||||
pointer=daveNewPDU();
|
||||
}
|
||||
|
||||
/* ~PDU(){
|
||||
Console.WriteLine("~PDU()");
|
||||
daveFree(pointer);
|
||||
}
|
||||
*/
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern void daveAddVarToReadRequest(IntPtr p, int area, int DBnum, int start, int bytes);
|
||||
public void addVarToReadRequest(int area, int DBnum, int start, int bytes) {
|
||||
daveAddVarToReadRequest(pointer, area, DBnum, start, bytes);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern void daveAddBitVarToReadRequest(IntPtr p, int area, int DBnum, int start, int bytes);
|
||||
public void addBitVarToReadRequest(int area, int DBnum, int start, int bytes) {
|
||||
daveAddBitVarToReadRequest(pointer, area, DBnum, start, bytes);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern void daveAddVarToWriteRequest(IntPtr p, int area, int DBnum, int start, int bytes, byte[] buffer);
|
||||
public void addVarToWriteRequest(int area, int DBnum, int start, int bytes, byte[] buffer) {
|
||||
daveAddVarToWriteRequest(pointer, area, DBnum, start, bytes, buffer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern void daveAddBitVarToWriteRequest(IntPtr p, int area, int DBnum, int start, int bytes, byte[] buffer);
|
||||
public void addBitVarToWriteRequest(int area, int DBnum, int start, int bytes, byte[] buffer) {
|
||||
daveAddBitVarToWriteRequest(pointer, area, DBnum, start, bytes, buffer);
|
||||
}
|
||||
|
||||
} // class PDU
|
||||
|
||||
public class resultSet:pseudoPointer {
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern IntPtr daveNewResultSet();
|
||||
public resultSet() {
|
||||
pointer=daveNewResultSet();
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern void daveFreeResults(IntPtr rs);
|
||||
~resultSet(){
|
||||
// Console.WriteLine("~resultSet(1)");
|
||||
daveFreeResults(pointer);
|
||||
// Console.WriteLine("~resultSet(2)");
|
||||
// daveFree(pointer);
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
protected static extern int daveGetErrorOfResult(IntPtr rs, int number);
|
||||
public int getErrorOfResult(int number) {
|
||||
return daveGetErrorOfResult(pointer, number);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern int setPort(
|
||||
[MarshalAs(UnmanagedType.LPStr)] string portName,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string baud,
|
||||
int parity
|
||||
);
|
||||
|
||||
[DllImport("libnodave.dll" /*, PreserveSig=false */ )]
|
||||
public static extern int openSocket(
|
||||
int port,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string portName
|
||||
);
|
||||
|
||||
[DllImport("libnodave.dll" /*, PreserveSig=false */ )]
|
||||
public static extern int openS7online(
|
||||
[MarshalAs(UnmanagedType.LPStr)] string portName
|
||||
);
|
||||
|
||||
[DllImport("libnodave.dll" /*, PreserveSig=false */ )]
|
||||
public static extern int closePort(
|
||||
int port
|
||||
);
|
||||
|
||||
[DllImport("libnodave.dll" /*, PreserveSig=false */ )]
|
||||
public static extern int closeSocket(
|
||||
int port
|
||||
);
|
||||
|
||||
[DllImport("libnodave.dll" )]
|
||||
public static extern int closeS7online(
|
||||
int port
|
||||
);
|
||||
|
||||
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern float toPLCfloat(float f);
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern int daveToPLCfloat(float f);
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern int daveSwapIed_32(int i);
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
public static extern int daveSwapIed_16(int i);
|
||||
|
||||
public static int getS16from(byte[] b, int pos) {
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
byte[] b1=new byte[2];
|
||||
b1[1]=b[pos+0];
|
||||
b1[0]=b[pos+1];
|
||||
return BitConverter.ToInt16(b1, 0);
|
||||
}
|
||||
else
|
||||
return BitConverter.ToInt16(b, pos);
|
||||
}
|
||||
|
||||
public static int getU16from(byte[] b, int pos) {
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
byte[] b1=new byte[2];
|
||||
b1[1]=b[pos+0];
|
||||
b1[0]=b[pos+1];
|
||||
return BitConverter.ToUInt16(b1, 0);
|
||||
}
|
||||
else
|
||||
return BitConverter.ToUInt16(b, pos);
|
||||
}
|
||||
|
||||
public static int getS32from(byte[] b, int pos) {
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
byte[] b1=new byte[4];
|
||||
b1[3]=b[pos];
|
||||
b1[2]=b[pos+1];
|
||||
b1[1]=b[pos+2];
|
||||
b1[0]=b[pos+3];
|
||||
return BitConverter.ToInt32(b1, 0);
|
||||
}
|
||||
else
|
||||
return BitConverter.ToInt32(b, pos);
|
||||
}
|
||||
|
||||
public static uint getU32from(byte[] b, int pos) {
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
byte[] b1=new byte[4];
|
||||
b1[3]=b[pos];
|
||||
b1[2]=b[pos+1];
|
||||
b1[1]=b[pos+2];
|
||||
b1[0]=b[pos+3];
|
||||
return BitConverter.ToUInt32(b1, 0);
|
||||
}
|
||||
else
|
||||
return BitConverter.ToUInt32(b, pos);
|
||||
}
|
||||
|
||||
public static float getFloatfrom(byte[] b, int pos) {
|
||||
if (BitConverter.IsLittleEndian) {
|
||||
byte[] b1=new byte[4];
|
||||
b1[3]=b[pos];
|
||||
b1[2]=b[pos+1];
|
||||
b1[1]=b[pos+2];
|
||||
b1[0]=b[pos+3];
|
||||
return BitConverter.ToSingle(b1, 0);
|
||||
}
|
||||
else
|
||||
return BitConverter.ToSingle(b, pos);
|
||||
}
|
||||
|
||||
|
||||
[DllImport("libnodave.dll"/*, PreserveSig=false */ )]
|
||||
private static extern int daveAreaName(int area);
|
||||
|
||||
[DllImport("libnodave.dll")]
|
||||
private static extern int daveBlockName(int blockType);
|
||||
[DllImport("libnodave.dll")]
|
||||
private static extern void daveStringCopy(int i, byte[] c);
|
||||
|
||||
public static string blockName(int blockType) {
|
||||
byte[] s=new byte[255];
|
||||
int i=daveBlockName(blockType);
|
||||
daveStringCopy(i, s);
|
||||
string st="";
|
||||
i=0;
|
||||
while (s[i]!=0) {
|
||||
st=st+(char)s[i];
|
||||
i++;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
public static string areaName(int blockType) {
|
||||
byte[] s=new byte[255];
|
||||
int i=daveAreaName(blockType);
|
||||
daveStringCopy(i, s);
|
||||
string st="";
|
||||
i=0;
|
||||
while (s[i]!=0) {
|
||||
st=st+(char)s[i];
|
||||
i++;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Changes:
|
||||
03/30/2006 bug fix: removed double calls to daveFree in nested destructors.
|
||||
11/21/2006 bug fix: applied patches from Johann Gail.
|
||||
Version 0.8.4.5
|
||||
07/10/09 Added closeSocket()
|
||||
*/
|
||||
BIN
Dot.NET/libnodave.net.dll
Executable file
BIN
Dot.NET/libnodave.net.dll
Executable file
Binary file not shown.
2
Dot.NET/mono.bat
Executable file
2
Dot.NET/mono.bat
Executable file
@@ -0,0 +1,2 @@
|
||||
bin\mcs -t:library libnodave.net.cs
|
||||
|
||||
7
Dot.NET/mono.sh
Executable file
7
Dot.NET/mono.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
mcs /t:library libnodave.net.cs
|
||||
mcs /r:libnodave.net.dll CS/testMPI.cs
|
||||
mcs /r:libnodave.net.dll CS/testS7online.cs
|
||||
mcs /r:libnodave.net.dll CS/simpleMPI.cs
|
||||
mcs /r:libnodave.net.dll CS/simplePPI.cs
|
||||
mcs /r:libnodave.net.dll CS/simpleISO_TCP.cs
|
||||
mbas /r:./libnodave.net.dll VB/simpleMPI2.vb
|
||||
189
FAQ.de.txt
Normal file
189
FAQ.de.txt
Normal file
@@ -0,0 +1,189 @@
|
||||
Fragen, die mir schon oefter gestellt wurden und die Antworten:
|
||||
|
||||
Q: Meine VB,.NET oder Delphi-Anwendung funktioniert nicht. Ich vermute, Libnodave funktioniert
|
||||
nicht mit meiner Hardware oder funktioniert gar nicht. Kannst du mir helfen?
|
||||
A: Du kannst ganz einfach herausfinden, ob Libnodave mit deiner Hardware, SPS, Adapter
|
||||
usw. arbeitet: Probierer es mit den vorkompilierten Testprogrammen. Wenn die nicht funktionieren
|
||||
(auch die vorgeschlagenen Optionen probieren, wenn welche vorgeschlagen werden), ist es ganz
|
||||
klar ein Fehler in Libnodave.
|
||||
Wenn sie funktionieren, liegt es an deiner Anwendung (oder, selten, koennte das Problem in
|
||||
der Schnittstelle zu der verwendeten Programmiersprache liegen).
|
||||
|
||||
Q: Kannst du mir helfen?
|
||||
A: Bevor du fragst, probiere die Testprogramme wie oben beschrieben. Wenn die bei dir nicht
|
||||
funktionieren, schicke mir die Ausgabe mit der Debug-Option, z.B.:
|
||||
testMPI -d COM1 >debugout.txt
|
||||
Wenn sie funktionieren, deine Anwendung aber nicht, probier mal:
|
||||
Fuege die Zeile "daveSetDebug(daveDebugAll)" vor allen anderen Aufrufen von Libnodave in
|
||||
deinen Code ein.
|
||||
Dann versuche:
|
||||
deineAnwendung >debugout.txt
|
||||
Fuer die Leute, die mit Maeusen gross wurden und die Kommandozeile nicht mehr kennen:
|
||||
Das funktioniert sogar mit MS-Excel. Erzeuge eine neue Tabelle, importiere das VBA_Modul,
|
||||
- nimm das "rem" weg vor "call daveSetDebug(daveDebugAll)" am Anfang von sub initialize,
|
||||
- Speichere das Arbeitsblatt.
|
||||
- Starte dann von der Kommandozeile (Dos-Box, Ausfuehren/cmd):
|
||||
excel testsheet >debugout.txt
|
||||
Alle Debug-Ausgaben gelangen in die Datei debugout.txt.
|
||||
Wenn meine Zeit knapp wird, schmeisse ich Mails ohne Debug-Ausgabe weg!
|
||||
|
||||
Q: Welches E-mail Format bevorzugst du?
|
||||
A: Na ja, niemand hat danach gefragt, aber ich ziehe PUREN TEXT vor.
|
||||
|
||||
Q: Ich moechte auslesen, ob meine CPU in RUN oder STOP ist. Gibt es dafuer eine Funktion?
|
||||
A: Nein, keine spezialisierte. Verwende bei S7-300/400 daveReadSZL, um die SZL Systemzustandslisten
|
||||
zu lesen. Step7 macht das auch so. Informationen ueber IDs und Indizes findest du in der Siemens
|
||||
Dokumentation. Der Zustand aller CPU-LEDs ist in ID 25 (19hex), index 0.
|
||||
Bei der S7-200 befindet sich diese Information irgendwo in den Systemdaten.
|
||||
|
||||
Q: Ich versuche, Libnodave mit einem Debugger nachzuvollziehen. Ich brauche Hilfe?
|
||||
A: Es gibt kaum einen Grund, Libnodave mit einem Debugger zu untersuchen, ausser du vermutest eine
|
||||
der fogenden Sachen:
|
||||
- Speicherprobleme (memory leaks)
|
||||
- Bereichsueberschreitungen (range overflows) bei Zahlen oder Array-Indizes.
|
||||
- Probleme bei der Uebergabe von Parametern an Bibliotheksfunktionen
|
||||
Im letzteren Fall uebersetze besser Libnodave neu, nachdem du das Kommentarzeichen vor
|
||||
#define DEBUG_CALLS in nodave.c entfernt hast.
|
||||
Um Probleme mit SPS und Adaptern zu finden, ist die Debug-Ausgabe der weit bessere Weg.
|
||||
Sie zeigt dir alles, was von und zu SPS/Adapter gesendet und empfangen wird und sie
|
||||
zeigt dir das, was wichtig ist, anstatt es aus Speicher und Registern herauszufinden.
|
||||
|
||||
Q: Kannst du mir eine Dokumentation ueber die S7-Kommunikation oder das MPI-Protokoll geben?
|
||||
A: Nein, kann ich nicht. Was ich darueber weiss, stammt aus "reverse engineering". Das
|
||||
bedeutet, eine Menge Pakete mitzuschreiben, versuchen, einen Sinn hineinzuinterpretieren
|
||||
und sie mit eigenem Code nachzubilden. Wenn in Libnodave Dinge Namen haben, so geben diese
|
||||
meine gegenwaertige Hypothese wieder. Ich koennte versuchen, Dokumentation zu schreiben, aber
|
||||
die wuerde immer einen Schritt hinter dem Code hinterherhinken: Der Code kann an der gegebenen
|
||||
Hardware, also an der Realitaet, getestet werden, die Dokumentation nicht. Und der Code ist
|
||||
recht gut dokumentiert...
|
||||
|
||||
Q: Also, warum gibt es diese komplizierten Strukturen (structs)?
|
||||
A: Was kompliziert erscheint, sind wahrscheinlich zunaechst die Zeiger auf protokollspezifische
|
||||
Funktionen. In Wahrheit machen sie die Bibliothek einfacher in zweierlei Hinsicht:
|
||||
- Erstens trennen sie die Bildung der Pakete vom Transport. Wenn jemand herausfindet, wie man
|
||||
mit der S7 etwas neues machen kann, reicht es, die Paketbildung zu implementieren und schon
|
||||
wird es hoechstwahrscheinlich mit jedem Transportprotokoll funktionieren. Wenn andererseits
|
||||
ein neuer Transportmechanismus hinzukommt, werden wahrscheinlich alle Functionen damit
|
||||
funktionieren, sobald der Transport an sich funktioniert.
|
||||
Version 0.8 zeigt das klar anhand der Implementierung des Transports ueber s7online.dll.
|
||||
- Kommerzielle Bibliotheken, die ich gesehen habe, haben meist getrennte Saetze von Funktionen
|
||||
fuer die 200 und die 300/400 Familie. Libnodave hat das nicht. So musst du weniger ueber das
|
||||
API der Bibliothek lernen waehrend deine Anwendung ohne Veraenderung des Codes mehr kann.
|
||||
|
||||
Q: Warum exportierst du alle diese Strukturen, wenn du sagst, man braucht sie fuer keinerlei
|
||||
Anwendung?
|
||||
A: Sie sind nicht ganz bedeutungslos. Es sind auch eine Menge Funktionen dabei, die
|
||||
"Zwischenschritte" duechfhren un normalerweise fr den Endanwender von keinem Nutzen sind.
|
||||
Dennoch werden sie aus der .dll exportiert.
|
||||
- Das ist alles verfuegbar - im Sinne von Open Source - fueer diejenigen, die eigene
|
||||
Experimente machen wollen. Es mag ja Moeglichkeiten gebn, an die ich nicht gedacht habe.
|
||||
- Wenigstens einmal konnte ich einem Benutzer helfen, eine neue Funktion (daveForce200) zu
|
||||
implementiern. Er mute nur ca. 20 Zeilen in sein Programm einfuegen, die zum groessten Teil
|
||||
solche Zwischenschritte beim Zusammenstellen eines Pakets und zur Analyse der Antwort
|
||||
aufriefen, wie z.B. _daveAddData.
|
||||
|
||||
Q: Warum gibts keine Funktionen wie readOutputs, readInputs, readData ?
|
||||
A: Andere Bibliotheken haben ueblicherweise separate Functionen um Eingaenge, Ausgaenge,
|
||||
Merker, Datenbausteine zu lesen. Libnodave hat das nicht. Schon wieder musst du weniger
|
||||
ueber das API lernen.
|
||||
Q: Warum gibt es keine Funktionen wie readBytes, readIntegers, readDWords, readFloat ?
|
||||
A: Andere Bibliotheken haben oft separate Funktionen um Integers, Worte oder Fliesskomma-
|
||||
zahlen zu lesen. Libnodave hat das nicht. Der Grund ist: Wenn du einen DB (oder einen
|
||||
anderen Speicherbereich in der SPS) hast, der Daten verschiedener Types enthaelt, koenntest
|
||||
du mit solchen Functionen nur Teile davon lesen. Oder du benutzt readBytes um den Speicher
|
||||
als eine Reihe von Bytes zu lesen und bist bei der Umwandlung auf dich allein gestellt.
|
||||
Libnodave liest generell den ganzen Block als Bytes und stellt dir dann Funktionen zur
|
||||
Umwandlung von/in SPS-Datentypen und Byte-Anordnung zur Verfuegung.
|
||||
|
||||
Q: Ich versuche, meinen Quellcode zu kompilieren, der nodave.h einbindet. Warum erhalte ich:
|
||||
"#error Fill in what you need for your OS or API" ?
|
||||
A: Libnodave mu unter verschiedenen Betriebssystemen verschiedene Funktionen nutzen,
|
||||
um Daten byteweise von seriellen Schnittstellen oder TCP/IP streams zu lesen.
|
||||
Diese Funktionen sind betriebssystemspezifisch. Du mut spezifizieren fr welches BS du
|
||||
kompilierst. Definiere BCCWIN fuer Windows und LINUX fuer Linux oder andere Unix-artige
|
||||
BS. Ich benutze -DBCCWIN oder -DLINUX beim Aufruf der Compiler aus einem Makefile. Wenn du
|
||||
eine IDE (integrierte Entwicklungsumgebung) nutzt, entnimm der Dokumentation der IDE wie das
|
||||
dort geht. Wenn du es nicht herausfinden kannst, kannst du dir auch helfen indem du die
|
||||
#defines in deinen Quellcode schreibst (was bedeutet, dass dein Quellcode nicht mehr
|
||||
ohne Aenderungen auf ein anderes System portiert werden kann). Beispiel:
|
||||
|
||||
...
|
||||
#define BCCWIN // if you work on windows
|
||||
#include nodave.h // or nodavesimple.h, but NEVER both
|
||||
#include setport.h // if your code works with serial connections
|
||||
#include openSocket.h // if your code works with TCP/IP
|
||||
...
|
||||
Q: Ich versuche, libnodave aus dem Quellcode zu kompilieren. Es gibt Probleme.
|
||||
A: - Du brauchst Libnodave nicht selbst zu kompilieren. Du wrdest das mit anderen DLLs (Windows)
|
||||
oderr .sos (gemeinsam genutzte Bibliotheken unter Linux) auch nicht machen. Normalerweise
|
||||
linkt man solche Bibliotheken dynamisch zum eigenen Code.
|
||||
- Nichtsdestotrotz steht dir der Quellcode zur Verfuegunge und du moechtes ihn oder nur die
|
||||
benoetigten Teile rekompilieren usw..
|
||||
- Du solltest wissen, dass die S7 die Motorola- (big endian, hchstwertiges byte zuerst)
|
||||
Byteanordnung (endianness) verwendet, waehrend Intel-Prozessoren Intel-Byteanordnung
|
||||
(little endian, niederwertigstes Byte zuerst). Auf Intel- und aehnlichen Maschinen
|
||||
muss Libnodave Mehbyte-Werte umsortieren. Dies geschieht mittels der Funktionen daveGetS2(),
|
||||
daveGetU2(), daveGetFloat() usw.. Der Code zur Konvertierung wird nur mitkompiliert
|
||||
wenn du DAVE_LITTLE_ENDIAN definierst. Ansonsten wird "big endian" vorausgesetzt.
|
||||
- Beachte, dass ich die publizierten Versionen von Libnodave mit gcc (fuer Linux) und MSVC++
|
||||
(fuer windows) kompiliere. Dazu verwende ich das Skript buildall um Linux und Windows
|
||||
Release-Versionen und Testprogramme auf einem Linux-Rechner zu erzeugen. Buildall benutzt
|
||||
seinerseits das make von Linux mit MAKEFILE.VC.WINE um den MSVC++-Compiler fuer die
|
||||
Windows-Versionen aufzurufen. Es gibt auch ein MAKEFILE.VC das auf einem Windows-System
|
||||
mittels nmake dasselbe leisten sollte, aber es koennte nicht auf dem neuesten Stand sein :-(
|
||||
Wenn du Zweifel hast, welche Compileroptionen oder Quelldateien noetig sind, schau in
|
||||
MAKEFILE.VC.WINE nach!
|
||||
|
||||
Q: Ich moechte Libnodave fuer ein anderes Betriebssystem kompilieren. Welche Anpassungen
|
||||
muss ich vornehmen?
|
||||
A: - Ich nehme mal an, dass dein Betriebssystem ein 32-Bit-System ist und der zugehoerige
|
||||
Compiler int als 32-Bit-Zahl behandelt. Wenn nicht, wird es schwierig!
|
||||
- Du brauchst funktionsgleichen Ersatz fuer setport.c oder setportw.c und openSocket.c oder
|
||||
openSocketw.c
|
||||
- nodave.h: Du musst ein struct _daveOSserialType definieren, dass folgende Elemente beinhaltet:
|
||||
rfd: Ein Datentyp, der eine serielle Schnittstelle oder ein TCP socket bei einem Lesezugriff
|
||||
indentifiziert.
|
||||
wfd: Ein Datentyp, der eine serielle Schnittstelle oder ein TCP socket bei einem Schreibzugriff
|
||||
indentifiziert.
|
||||
- nodave.c: Du musst die Funktionen stdread() und stdwrite() implementieren, die Bytes
|
||||
von/an eine serielle Schnittstelle in/aus einem Puffer lesen/schreiben.
|
||||
|
||||
Q: Gibt es eine Funktion um die Struktur eines Datenbausteins zu lesen? Variablen und ihre
|
||||
Datentypen ?
|
||||
A: Nein. Die Strukturinformation steht nur in Step7 und nur vor der Compilierung verfuegbar.
|
||||
Sie wird nicht in die SPS selbst uebertragen. Es ist dasselbe, wenn du ein neues Projekt
|
||||
anlegst und den Programmcode aus der SPS laedtst: Von den Datenbausteinen bleiben nur
|
||||
Byte-Arrays.
|
||||
|
||||
Q: Ich habe Probleme, auf Eingaenge zu schreiben. Koennen Sie mir hefen?
|
||||
A: Zunaechst gibt es zwei Typen von "Eingaengen": 1. Periphere Adressen. Das ist das, was Sie
|
||||
mit daveP ansprechen, oder, in einen SPS-Programm, mittels L PEW <adresse>. Zugriffe auf
|
||||
diese Adressen sind echte Schreib- oder Lesezugriffe auf die Hardware und es gibt keine
|
||||
Moeglichkeit, die Hardware von Eingaengen zu schreiben.
|
||||
2. Prozessabbild der Ein- und Ausgaenge. Das ist was Programmierer von Siemens-SPS
|
||||
normalerweise als Ein- und Ausgaenge ansprechen, wie bei:
|
||||
L EW <Adresse>
|
||||
or
|
||||
U E 2.5
|
||||
Zugriffe auf diese Adressen sprechen NICHT die Hardware sondern einen speziellen Speicherbereich
|
||||
an. Der Zustand der Eingaenge wird in jedem Zyklus in diesen Speicherbereich kopiert, bevor
|
||||
das Anwenderprogramm ausgefhrt wird. Wenn Sie mittels daveInputs dorthin schreiben, werden die
|
||||
Werte vor dem naechsten Zyklus ueberschrieben.
|
||||
Ob Ihr SPS-Programm oder Ihre Libnodave-Anwendung die geschriebenen Werte "sehen" wird, ist
|
||||
ein zeitlicher Wettlauf.
|
||||
|
||||
Q: Ist es moeglich, mehrere (bis zu 3) Bits gleichzeitig in die SPS zu schreiben?
|
||||
Ich moechte "Read-modify-write"-Techniken vermeiden und das Schreiben so "atomar" wie moeglich
|
||||
halten.
|
||||
A: daveWriteBits() stellt eine "atomare" Schreibfunktion bereit, aber nur fr ein einzelnes Bit.
|
||||
Der Parameter "length" bei daveWriteBits() muss 1 sein, andere Werte liefern Fehler bei den
|
||||
CPUs die ich kenne. Warum also ist der Parameter vorhanden? Es gibt ein entsprechendes Feld
|
||||
in der Nachricht, das in anderen Faellen die Zahl der Bits angibt.
|
||||
|
||||
Q: Kann das ("atomares" Schreiben auf 3 Bits) mit daveWriteBits() erreicht werden oder muss
|
||||
ich mehrere Variablen mit einer PDU schreiben?
|
||||
A: Es kann NICHT mit daveWriteBits() erreicht werden, jedenfalls mit den CPUs die ich kenne. Ob
|
||||
das I know. Whether Schreiben mehrerer Variablen mit einer PDU atomar ist, weiss ich nicht.
|
||||
Wenn Sie das SPS-Programm verndern koennen, denke ich das Beste waere, die 3 Bits in ein Byte
|
||||
zu packen, dessen andere Bits nicht gebraucht werden.
|
||||
|
||||
122
MAKEFILE.VC.WINE
Normal file
122
MAKEFILE.VC.WINE
Normal file
@@ -0,0 +1,122 @@
|
||||
#
|
||||
# Makefile to build a Windows Version of LIBNODAVE using VC++
|
||||
# from Microsoft under wine. The Makefile itself is executed by
|
||||
# good old GNU make.
|
||||
#
|
||||
#
|
||||
# Make the "alien" suffixes known:
|
||||
#
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .obj .h .c .cpp
|
||||
#
|
||||
# type 'make' to build libnodave.dll and some statically linked test programs.
|
||||
# type 'make dynamic' to make libnodave.dll and some dynamically linked test programs.
|
||||
#
|
||||
# The directories where the windows tools and libs are:
|
||||
#
|
||||
#VCPATH=e:\programme\microsoft visual C++ Toolkit 2003
|
||||
#SDKPATH=e:\programme\microsoft platform sdk
|
||||
VCPATH=c:/vc
|
||||
SDKPATH=c:/psdk
|
||||
|
||||
INCPATH=$(VCPATH)/include
|
||||
INCPATH2="$(SDKPATH)/include"
|
||||
INCPATH3="$(SDKPATH)/include/crt"
|
||||
|
||||
CC=wine $(VCPATH)/bin/cl
|
||||
LL=wine $(VCPATH)/bin/link
|
||||
|
||||
CFLAGS= -I$(INCPATH) -I$(INCPATH2) -I$(INCPATH3) -c -DBCCWIN -DDAVE_LITTLE_ENDIAN -TC
|
||||
CPPFLAGS= -I$(INCPATH) -I$(INCPATH2) -I$(INCPATH3) -c -DBCCWIN -DDAVE_LITTLE_ENDIAN
|
||||
LFLAGS = /LIBPATH:"$(VCPATH)\lib"
|
||||
LLFLAGS = /LIBPATH:"$(VCPATH)\lib" /DEF:libnodave.DEF
|
||||
L2FLAGS = /LIBPATH:"$(VCPATH)\lib" /DEF:s7onlinx.DEF
|
||||
|
||||
PROGRAMS=testMPI.exe testPPI.exe testAS511.exe \
|
||||
testPPI_IBH.exe testPPI_IBHload.exe testPPIload.exe \
|
||||
testMPIload.exe testISO_TCP.exe testISO_TCPload.exe testIBH.exe testMPI_IBHload.exe \
|
||||
testS7online.exe testNLpro.exe
|
||||
|
||||
DYNAMIC_PROGRAMS=testMPId.exe testPPId.exe testISO_TCPd.exe testIBHd.exe testPPI_IBHd.exe
|
||||
|
||||
LIBRARIES=libnodave.dll
|
||||
|
||||
SERIAL_OBJECTS=nodave.obj setportw.obj
|
||||
|
||||
all: $(LIBRARIES) $(PROGRAMS)
|
||||
|
||||
dynamic: $(DYNAMIC_PROGRAMS)
|
||||
|
||||
testISO_TCP.exe: nodave.obj openSocketw.obj testISO_TCP.obj
|
||||
$(LL) $(LFLAGS) testISO_TCP.obj openSocketw.obj nodave.obj "$(SDKPATH)\lib\ws2_32.lib" /OUT:$@
|
||||
testMPI.exe: testMPI.obj $(SERIAL_OBJECTS)
|
||||
$(LL) $(LFLAGS) $(SERIAL_OBJECTS) testMPI.obj "$(SDKPATH)\lib\ws2_32.lib" /OUT:$@
|
||||
testIBH.exe: openSocketw.obj nodave.obj testIBH.obj
|
||||
$(LL) $(LFLAGS) testIBH.obj openSocketw.obj nodave.obj "$(SDKPATH)\lib\ws2_32.lib" /OUT:$@
|
||||
testIBHd.exe: libnodave.dll testIBH.obj
|
||||
$(LL) $(LFLAGS) testIBH.obj libnodave.lib /OUT:$@
|
||||
testPPI_IBH.exe: openSocketw.obj nodave.obj testPPI_IBH.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testPPI_IBH.obj "C:\\psdk\\lib\\ws2_32.lib" /OUT:$@
|
||||
testPPI_IBHd.exe: libnodave.dll testPPI_IBH.obj
|
||||
$(LL) $(LFLAGS) testPPI_IBH.obj libnodave.lib /OUT:$@
|
||||
testMPId.exe: libnodave.dll testMPI.obj
|
||||
$(LL) $(LFLAGS) testMPI.obj libnodave.lib /OUT:$@
|
||||
testPPI.exe: testPPI.obj nodave.obj setportw.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testPPI.obj "C:\\psdk\\lib\\ws2_32.lib" /out:$@
|
||||
testPPId.exe: libnodave.dll testPPI.obj
|
||||
$(LL) $(LFLAGS) testPPI.obj libnodave.lib /OUT:$@
|
||||
testISO_TCPd.exe: libnodave.dll testISO_TCP.obj
|
||||
$(LL) $(LFLAGS) testISO_TCP.obj libnodave.lib /OUT:$@
|
||||
testPPIload.exe: testPPIload.obj $(SERIAL_OBJECTS)
|
||||
$(LL) $(LFLAGS) testPPIload.obj $(SERIAL_OBJECTS) "$(SDKPATH)\lib\ws2_32.lib" /OUT:$@
|
||||
testMPIload.exe: testMPIload.obj $(SERIAL_OBJECTS)
|
||||
$(LL) $(LFLAGS) testMPIload.obj $(SERIAL_OBJECTS) "$(SDKPATH)\lib\ws2_32.lib" /OUT:$@
|
||||
testISO_TCPload.exe: nodave.obj openSocketw.obj testISO_TCPload.obj
|
||||
$(LL) $(LFLAGS) testISO_TCPload.obj openSocketw.obj nodave.obj "C:\\psdk\\lib\\ws2_32.lib" /out:testISO_TCPload.exe
|
||||
testMPI_IBHload.exe: nodave.obj openSocketw.obj testMPI_IBHload.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testMPI_IBHload.obj "C:\\psdk\\lib\\ws2_32.lib" /out:testMPI_IBHload.exe
|
||||
testPPI_IBHload.exe: nodave.obj openSocketw.obj testPPI_IBHload.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testPPI_IBHload.obj "C:\\psdk\\lib\\ws2_32.lib" /out:testPPI_IBHload.exe
|
||||
testAS511.exe: testAS511.obj nodave.obj setportw.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testAS511.obj "C:\\psdk\\lib\\ws2_32.lib" /out:$@
|
||||
testNLpro.exe: testNLpro.obj nodave.obj openSocketw.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testNLpro.obj "C:\\psdk\\lib\\ws2_32.lib" /out:$@
|
||||
libnodave.dll: nodave.obj setportw.obj openSocketw.obj openS7online.obj
|
||||
$(LL) $(LLFLAGS) /DLL nodave.obj setportw.obj openSocketw.obj openS7online.obj "C:\\psdk\\lib\\ws2_32.lib" /OUT:libnodave.dll
|
||||
testS7online.exe: testS7online.obj nodave.obj openS7online.obj
|
||||
$(LL) $(LFLAGS) nodave.obj testS7online.obj openS7online.obj "C:\\psdk\\lib\\ws2_32.lib" "C:\\psdk\\lib\\User32.lib" /out:$@
|
||||
#
|
||||
# delete all but the sources:
|
||||
#
|
||||
clean:
|
||||
rm -f *.tds
|
||||
rm -f *.il?
|
||||
rm -f *.lib
|
||||
rm -f *.obj
|
||||
rm -f *.dll
|
||||
rm -f *.exe
|
||||
rm -f *.map
|
||||
rm -f *.exp
|
||||
#
|
||||
# The general rule to build create an .obj:
|
||||
#
|
||||
.c.obj:
|
||||
$(CC) $(CFLAGS) $<
|
||||
.cpp.obj:
|
||||
$(CC) $(CPPFLAGS) $<
|
||||
#
|
||||
# Special rules for those objects that are part of the .dll:
|
||||
#
|
||||
nodave.obj: nodave.c nodave.h
|
||||
$(CC) $(CFLAGS) -DDOEXPORT nodave.c
|
||||
setportw.obj: setportw.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT setportw.c
|
||||
openSocketw.obj: openSocketw.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT openSocketw.c
|
||||
openS7online.obj: openS7online.c openS7online.h
|
||||
$(CC) $(CFLAGS) -DDOEXPORT openS7online.c
|
||||
s7fake.obj: s7fake.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT s7fake.c
|
||||
getHandle.obj: getHandle.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT getHandle.c
|
||||
|
||||
86
MAKEFILE.WINE
Normal file
86
MAKEFILE.WINE
Normal file
@@ -0,0 +1,86 @@
|
||||
#
|
||||
# Makefile to build a Windows Version of LIBNODAVE using the free command line tools
|
||||
# from Borland under LINUX and WINE.
|
||||
# For usage with WINE under Linux only.
|
||||
# Whether YOU can use it may depend on your WINE setup.
|
||||
# So don't blame me!
|
||||
#
|
||||
#
|
||||
# type 'make' to build libnodave.dll and some statically linked test programs.
|
||||
# type 'make dynamic' to make libnodave.dll and some dynamically linked test programs.
|
||||
#
|
||||
# The directory where the tools are:
|
||||
#
|
||||
#BCCPATH=../bin
|
||||
BCCPATH=c:/BCC55/bin
|
||||
INCPATH=c:/BCC55
|
||||
LIBPATH=C:\BCC55\lib
|
||||
CC=wine $(BCCPATH)/bcc32
|
||||
LL=$(BCCPATH)/ilink32
|
||||
|
||||
CFLAGS= -I$(INCPATH)/include -c -DBCCWIN -DLITTLE_ENDIAN
|
||||
#CFLAGS= -I..\include -c -DBCCWIN -DLITTLE_ENDIAN
|
||||
|
||||
PROGRAMS=testMPI.exe testPPI.exe \
|
||||
testPPI_IBH.exe testPPI_IBHload.exe testPPIload.exe \
|
||||
testMPIload.exe testISO_TCP.exe testISO_TCPload.exe testIBH.exe testMPI_IBHload.exe
|
||||
|
||||
|
||||
DYNAMIC_PROGRAMS=testMPId.exe testPPId.exe testISO_TCPd.exe testIBHd.exe testPPI_IBHd.exe
|
||||
|
||||
LIBRARIES=libnodave.dll
|
||||
|
||||
all: $(PROGRAMS) $(LIBRARIES)
|
||||
|
||||
dynamic: $(DYNAMIC_PROGRAMS)
|
||||
|
||||
testISO_TCP.exe: nodave.obj openSocketw.obj testISO_TCP.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) $(LIBPATH)\c0x32 testISO_TCP.obj openSocketw.obj nodave.obj, testISO_TCP.exe,,CW32 IMPORT32
|
||||
testMPI.exe: setportw.obj nodave.obj testMPI.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) c0x32 setportw.obj nodave.obj testMPI.obj, testMPI.exe,,CW32 IMPORT32 ws2_32
|
||||
|
||||
testIBH.exe: openSocketw.obj nodave.obj testIBH.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 openSocketw.obj nodave.obj testIBH.obj, testIBH.exe,,CW32 IMPORT32 ws2_32
|
||||
|
||||
testIBHd.exe: libnodave.dll testIBH.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 testIBH.obj, testIBHd.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
|
||||
testPPI_IBH.exe: openSocketw.obj nodave.obj testPPI_IBH.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 openSocketw.obj nodave.obj testPPI_IBH.obj, testPPI_IBH.exe,,CW32 IMPORT32 ws2_32
|
||||
|
||||
testPPI_IBHd.exe: libnodave.dll testPPI_IBH.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 testPPI_IBH.obj, testPPI_IBHd.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
|
||||
testMPId.exe: libnodave.dll testMPI.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 testMPI.obj , testMPId.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
testPPI.exe: testPPI.obj nodave.obj setportw.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 setportw.obj nodave.obj testPPI.obj, testPPI.exe,,CW32 IMPORT32
|
||||
testPPId.exe: libnodave.dll testPPI.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 testPPI.obj, testPPId.exe,,libnodave CW32 IMPORT32 ws2_32
|
||||
testISO_TCPd.exe: libnodave.dll testISO_TCP.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 testISO_TCP.obj, testISO_TCPd.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
testPPIload.exe: nodave.obj setportw.obj testPPIload.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 setportw.obj nodave.obj testPPIload.obj, testPPIload.exe,,CW32 IMPORT32
|
||||
testMPIload.exe: nodave.obj setportw.obj testMPIload.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 setportw.obj nodave.obj testMPIload.obj, testMPIload.exe,,CW32 IMPORT32
|
||||
testISO_TCPload.exe: nodave.obj openSocketw.obj testISO_TCPload.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 openSocketw.obj nodave.obj testISO_TCPload.obj, testISO_TCPload.exe,,CW32 IMPORT32
|
||||
|
||||
testMPI_IBHload.exe: nodave.obj openSocketw.obj testMPI_IBHload.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 openSocketw.obj nodave.obj testMPI_IBHload.obj, testMPI_IBHload.exe,,CW32 IMPORT32
|
||||
|
||||
testPPI_IBHload.exe: nodave.obj openSocketw.obj testPPI_IBHload.obj
|
||||
$(LL) /r /Tpe /L$(LIBPATH) ..\lib\c0x32 openSocketw.obj nodave.obj testPPI_IBHload.obj, testPPI_IBHload.exe,,CW32 IMPORT32
|
||||
|
||||
libnodave.dll: nodave.obj setportw.obj openSocketw.obj
|
||||
$(LL) /v /C /Gn /w /Gk /r /Tpd /L$(LIBPATH) ..\lib\c0d32 nodave setportw openSocketw , libnodave.dll,,IMPORT32 CW32
|
||||
$(BCCPATH)/implib libnodave.lib libnodave.dll
|
||||
#
|
||||
# delete all but the sources:
|
||||
#
|
||||
clean:
|
||||
del *.tds
|
||||
del *.il?
|
||||
del *.lib
|
||||
del *.obj
|
||||
del *.dll
|
||||
141
Makefile
Normal file
141
Makefile
Normal file
@@ -0,0 +1,141 @@
|
||||
#
|
||||
# removed testUSB from programs. Use "make usb" to make it.
|
||||
# removed definitions for CYGWIN. There were no more differences versus LINUX
|
||||
#
|
||||
# These were the paths and names of the ARM cross compiling tools I tried:
|
||||
# The -Bstatic option was necessary to get statically linked files needed for ARM-simulator
|
||||
#
|
||||
# CC=/usr/local/arm/2.95.3/bin/arm-linux-gcc
|
||||
# LD=/usr/local/arm/2.95.3/bin/arm-linux-ld -Bstatic
|
||||
# LDFLAGS= -Wl,-Bstatic
|
||||
##LD=ld
|
||||
#
|
||||
# To test with g++ which does stricter type checking:
|
||||
#
|
||||
##CC=g++
|
||||
CFLAGS=-Wall -Winline -DLINUX -fPIC -DDAVE_LITTLE_ENDIAN
|
||||
CTFLAGS=-Wall -Winline -fPID -fPIC -DLINUX -DDAVE_LITTLE_ENDIAN
|
||||
CPPFLAGS=-fno-stack-protector -nostdlib -Wall -Winline -DLINUX -fPIC -DDAVE_LITTLE_ENDIAN
|
||||
#
|
||||
# The following is needed to enable workarounds for statements that do
|
||||
# not work on (some?) ARM processors:
|
||||
# It also helped on some machine running HP-UX.
|
||||
#
|
||||
#CFLAGS+=-DARM_FIX
|
||||
|
||||
|
||||
#-static -Wl,static -lc.a -static -lpthread.a -nostdlib
|
||||
#CFLAGS=-O0 -Wall -Winline
|
||||
PROGRAMS=testIBH testISO_TCP testMPI testPPI \
|
||||
testPPIload testMPIload ibhsim5 \
|
||||
isotest4 \
|
||||
testISO_TCPload testMPI_IBHload testPPI_IBHload testPPI_IBH \
|
||||
testNLpro \
|
||||
testAS511
|
||||
|
||||
|
||||
|
||||
# testISO2
|
||||
# testMPImin
|
||||
# testPPI_IBH
|
||||
|
||||
DYNAMIC_PROGRAMS=testMPId testPPId testISO_TCPd
|
||||
|
||||
LIBRARIES=libnodave.so
|
||||
|
||||
|
||||
all: $(PROGRAMS) $(LIBRARIES)
|
||||
install: libnodave.so
|
||||
cp libnodave.so /usr/lib
|
||||
cp nodave.h /usr/include
|
||||
ldconfig
|
||||
dynamic: $(DYNAMIC_PROGRAMS)
|
||||
usb: testUSB
|
||||
|
||||
nodave.o: nodave.h log2.h
|
||||
openSocket.o: openSocket.h nodave.h log2.h
|
||||
|
||||
testISO_TCP.o: benchmark.c nodavesimple.h
|
||||
testPPI.o: benchmark.c nodavesimple.h
|
||||
testPPIcpp.o: benchmark.c nodavesimple.h
|
||||
testMPI.o: benchmark.c nodavesimple.h
|
||||
testIBH.o: benchmark.c nodavesimple.h
|
||||
testPPI_IBH.o: benchmark.c nodavesimple.h
|
||||
testISO_TCPload.o: nodave.h
|
||||
testPPIload.o: nodave.h
|
||||
testMPIload.o: nodave.h
|
||||
testMPI_IBHload.o: nodave.h
|
||||
testPPI_IBHload.o: nodave.h
|
||||
testNLpro.o: benchmark.c nodavesimple.h
|
||||
|
||||
testISO_TCP: nodave.o openSocket.o testISO_TCP.o
|
||||
$(CC) $(LDFLAGS) nodave.o openSocket.o testISO_TCP.o -o testISO_TCP
|
||||
testISO2: nodave.o openSocket.o testISO2.o
|
||||
$(CC) $(LDFLAGS) nodave.o openSocket.o testISO2.o -o testISO2
|
||||
testISO_TCPd: nodave.o openSocket.o testISO_TCP.o
|
||||
$(CC) -lnodave testISO_TCP.o -o testISO_TCPd
|
||||
testPPIload: nodave.o setport.o testPPIload.o
|
||||
$(CC) $(LDFLAGS) nodave.o setport.o testPPIload.o -o testPPIload
|
||||
testMPI: setport.o testMPI.o nodave.o
|
||||
$(CC) $(LDFLAGS) setport.o nodave.o testMPI.o -o testMPI
|
||||
testMPImin: setport.o testMPImin.o nodave.o
|
||||
$(CC) $(LDFLAGS) setport.o nodave.o testMPImin.o -o testMPImin
|
||||
testMPId: setport.o testMPI.o nodave.o
|
||||
$(CC) -lnodave testMPI.o -o testMPId
|
||||
testMPIload: nodave.o setport.o testMPIload.o
|
||||
$(CC) $(LDFLAGS) nodave.o setport.o testMPIload.o -o testMPIload
|
||||
testMPI_IBHload: nodave.o openSocket.o testMPI_IBHload.o
|
||||
$(CC) $(LDFLAGS) nodave.o openSocket.o testMPI_IBHload.o -o testMPI_IBHload
|
||||
testPPI: nodave.o setport.o testPPI.o
|
||||
$(CC) $(LDFLAGS) nodave.o setport.o testPPI.o -o testPPI
|
||||
testPPId: nodave.o setport.o testPPI.o
|
||||
$(CC) -lnodave testPPI.o -o testPPId
|
||||
testISO_TCPload: nodave.o openSocket.o testISO_TCPload.o
|
||||
$(CC) $(LDFLAGS) nodave.o openSocket.o testISO_TCPload.o -o testISO_TCPload
|
||||
testIBH: openSocket.o testIBH.o nodave.o
|
||||
$(CC) $(LDFLAGS) openSocket.o nodave.o testIBH.o -o testIBH
|
||||
testPPI_IBH: openSocket.o testPPI_IBH.o nodave.o
|
||||
$(CC) $(LDFLAGS) openSocket.o nodave.o testPPI_IBH.o -o testPPI_IBH
|
||||
testPPI_IBHload: openSocket.o testPPI_IBHload.o nodave.o
|
||||
$(CC) $(LDFLAGS) openSocket.o nodave.o testPPI_IBHload.o -o testPPI_IBHload
|
||||
testPPIcpp: nodave.o setport.o testPPIcpp.o
|
||||
$(CC) $(LDFLAGS) nodave.o setport.o testPPIcpp.o -o testPPIcpp
|
||||
testMPI2: setport.o testMPI2.o nodave.o nodaveext.o
|
||||
$(CC) $(LDFLAGS) setport.o nodave.o nodaveext.o testMPI2.o -o testMPI2
|
||||
testAS511: setport.o testAS511.o nodave.o
|
||||
$(CC) $(LDFLAGS) setport.o nodave.o testAS511.o -o testAS511
|
||||
testUSB: testUSB.o nodave.o usbGlue.o usbGlue.h
|
||||
$(CC) $(LDFLAGS) nodave.o testUSB.o usbGlue.o -lusb -o testUSB
|
||||
testNLpro: openSocket.o testNLpro.o nodave.o
|
||||
$(CC) $(LDFLAGS) openSocket.o nodave.o testNLpro.o -o testNLpro
|
||||
crc: crc.o
|
||||
$(CC) $(LDFLAGS) crc.o -o crc
|
||||
crc3: crc3.o
|
||||
$(CC) $(LDFLAGS) crc3.o -o crc3
|
||||
testHTTP: nodave.o openSocket.o testHTTP.o
|
||||
$(CC) $(LDFLAGS) nodave.o openSocket.o testHTTP.o -o testHTTP
|
||||
ibhsim9.o: simProperties2.c blocklist.h
|
||||
ibhsim9: ibhsim9.o nodave.h nodave.o openSocket.o openSocket.h blocklist.o blocklist2.o setport.o
|
||||
$(CC) -pthread ibhsim9.o openSocket.o nodave.o blocklist.o blocklist2.o setport.o -o ibhsim9
|
||||
ibhsim10.o: simProperties2.c blocklist.h
|
||||
ibhsim10: ibhsim10.o nodave.h nodave.o openSocket.o openSocket.h blocklist.o blocklist2.o setport.o emulator.o
|
||||
$(CC) -lm -pthread ibhsim10.o openSocket.o nodave.o blocklist.o blocklist2.o setport.o emulator.o -o ibhsim10
|
||||
|
||||
|
||||
|
||||
libnodave.so: nodave.o setport.o openSocket.o
|
||||
$(LD) -shared nodave.o setport.o openSocket.o -o libnodave.so
|
||||
|
||||
ibhsim5.o: simProperties.c
|
||||
ibhsim5: ibhsim5.o nodave.h nodave.o openSocket.o openSocket.h
|
||||
$(CC) -pthread ibhsim5.o openSocket.o nodave.o -o ibhsim5
|
||||
isotest4: isotest4.o openSocket.o nodave.o nodave.h
|
||||
$(CC) $(LDFLAGS) -pthread isotest4.o openSocket.o nodave.o $(LIB) -o isotest4
|
||||
|
||||
clean:
|
||||
rm -f $(DYNAMIC_PROGRAMS)
|
||||
rm -f $(PROGRAMS)
|
||||
rm -f *.o
|
||||
rm -f *.so
|
||||
rm -f *~
|
||||
|
||||
BIN
Python/.DS_Store
vendored
Normal file
BIN
Python/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
Python/._.DS_Store
Normal file
BIN
Python/._.DS_Store
Normal file
Binary file not shown.
53
Python/.svn/all-wcprops
Normal file
53
Python/.svn/all-wcprops
Normal file
@@ -0,0 +1,53 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 39
|
||||
/pydave/!svn/ver/23/branches/galvano_KW
|
||||
END
|
||||
lamelle.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 50
|
||||
/pydave/!svn/ver/21/branches/galvano_KW/lamelle.py
|
||||
END
|
||||
nodave.db3
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 50
|
||||
/pydave/!svn/ver/20/branches/galvano_KW/nodave.db3
|
||||
END
|
||||
nodave.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 49
|
||||
/pydave/!svn/ver/20/branches/galvano_KW/nodave.py
|
||||
END
|
||||
davedefs.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 51
|
||||
/pydave/!svn/ver/21/branches/galvano_KW/davedefs.py
|
||||
END
|
||||
pydave.c
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 48
|
||||
/pydave/!svn/ver/23/branches/galvano_KW/pydave.c
|
||||
END
|
||||
nodave.cfg
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 49
|
||||
/pydave/!svn/ver/4/branches/galvano_KW/nodave.cfg
|
||||
END
|
||||
DB.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 44
|
||||
/pydave/!svn/ver/4/branches/galvano_KW/DB.py
|
||||
END
|
||||
Makefile
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 47
|
||||
/pydave/!svn/ver/4/branches/galvano_KW/Makefile
|
||||
END
|
||||
131
Python/.svn/entries
Normal file
131
Python/.svn/entries
Normal file
@@ -0,0 +1,131 @@
|
||||
8
|
||||
|
||||
dir
|
||||
23
|
||||
https://svn.ela-devel.de:8443/pydave/branches/galvano_KW
|
||||
https://svn.ela-devel.de:8443/pydave
|
||||
|
||||
|
||||
|
||||
2010-05-17T09:43:42.974289Z
|
||||
23
|
||||
michi
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bfb6778f-2709-48be-b937-866231387e0f
|
||||
|
||||
lamelle.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-04-28T20:20:48.000000Z
|
||||
e63e3cae1e178aa7fd4e6c640d7b001b
|
||||
2010-04-28T18:04:29.221042Z
|
||||
21
|
||||
michi
|
||||
has-props
|
||||
|
||||
nodave.db3
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-08-21T09:58:25.000000Z
|
||||
08a3a5d3f63d85e928ae9f1154f848c1
|
||||
2010-04-28T15:49:12.805101Z
|
||||
20
|
||||
michi
|
||||
has-props
|
||||
|
||||
nodave.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-04-29T10:52:36.000000Z
|
||||
05bb9a8dd369b4aaca0cde2c3d2b2116
|
||||
2010-04-28T15:49:12.805101Z
|
||||
20
|
||||
michi
|
||||
has-props
|
||||
|
||||
davedefs.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-04-28T20:20:48.000000Z
|
||||
cee85a6f1621af6127bead77008aaad5
|
||||
2010-04-28T18:04:29.221042Z
|
||||
21
|
||||
michi
|
||||
|
||||
pydave.c
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-05-17T09:44:36.000000Z
|
||||
16bf58efce37b920ba57038eb714b137
|
||||
2010-05-17T09:43:42.974289Z
|
||||
23
|
||||
michi
|
||||
|
||||
nodave.cfg
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-08-12T13:40:58.000000Z
|
||||
060d6bb8086126ba5091f5dd87a9ad32
|
||||
2009-08-06T14:59:39.609803Z
|
||||
4
|
||||
michi
|
||||
|
||||
DB.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-04-29T10:53:31.000000Z
|
||||
3e7a097c1c18ffdfb14ceb5b369c0f56
|
||||
2009-08-06T14:59:39.609803Z
|
||||
4
|
||||
michi
|
||||
has-props
|
||||
|
||||
initdata
|
||||
dir
|
||||
|
||||
Makefile
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-08-12T13:40:58.000000Z
|
||||
61fe59324770b5163b458fe0c0b21275
|
||||
2009-08-06T14:59:39.609803Z
|
||||
4
|
||||
michi
|
||||
|
||||
1
Python/.svn/format
Normal file
1
Python/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
5
Python/.svn/prop-base/DB.py.svn-base
Normal file
5
Python/.svn/prop-base/DB.py.svn-base
Normal file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
5
Python/.svn/prop-base/lamelle.py.svn-base
Normal file
5
Python/.svn/prop-base/lamelle.py.svn-base
Normal file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
5
Python/.svn/prop-base/nodave.db3.svn-base
Normal file
5
Python/.svn/prop-base/nodave.db3.svn-base
Normal file
@@ -0,0 +1,5 @@
|
||||
K 13
|
||||
svn:mime-type
|
||||
V 24
|
||||
application/octet-stream
|
||||
END
|
||||
5
Python/.svn/prop-base/nodave.py.svn-base
Normal file
5
Python/.svn/prop-base/nodave.py.svn-base
Normal file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
168
Python/.svn/text-base/DB.py.svn-base
Normal file
168
Python/.svn/text-base/DB.py.svn-base
Normal file
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/python2.4
|
||||
#!/opt/local/bin/python3.0
|
||||
|
||||
#import sqlite3 as sqlite
|
||||
from pysqlite2 import dbapi2 as sqlite
|
||||
from sys import exit
|
||||
import datetime
|
||||
|
||||
def connectdb (dbfile):
|
||||
"""
|
||||
Create connection to database
|
||||
return DB Object
|
||||
user gets information if failure
|
||||
"""
|
||||
try:
|
||||
db = sqlite.connect (dbfile, 15.0)
|
||||
return db
|
||||
except:
|
||||
print ("Couldnt connct to DB")
|
||||
exit (1)
|
||||
|
||||
|
||||
class DB:
|
||||
def __init__ (self, dbfile):
|
||||
self.db = connectdb (dbfile)
|
||||
|
||||
|
||||
def executesql (self, dbstring):
|
||||
"""
|
||||
exectutes sql in dbstring
|
||||
and returns cursor
|
||||
"""
|
||||
try:
|
||||
cursor = self.db.cursor ()
|
||||
cursor.execute (dbstring)
|
||||
except sqlite.OperationalError:
|
||||
print ("SQL exectution failed. Caused by: " + dbstring)
|
||||
raise Warning
|
||||
except sqlite.IntegrityError:
|
||||
print ("Double entry. Caused by: " + dbstring)
|
||||
raise Warning
|
||||
except sqlite.ProgrammingError:
|
||||
print ("Invalid SQL: " + dbstring)
|
||||
raise Warning
|
||||
except sqlite.Warning:
|
||||
pass
|
||||
|
||||
self.db.commit ()
|
||||
return cursor
|
||||
|
||||
|
||||
def getallclients (self):
|
||||
"""
|
||||
returns all available clients
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("SELECT id, client, proto, address, mpi, rack, slot FROM clients;")
|
||||
except:
|
||||
print ("couldn't get clients")
|
||||
raise Warning
|
||||
|
||||
return cursor.fetchall ()
|
||||
|
||||
|
||||
def getalllocations (self):
|
||||
"""
|
||||
returns all locations
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("SELECT * FROM locations")
|
||||
except:
|
||||
print ("couldn't get locations")
|
||||
raise Warning
|
||||
|
||||
return cursor.fetchall ()
|
||||
|
||||
|
||||
def getiopointsclient (self, client):
|
||||
"""
|
||||
returns all iopoints belong to client
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("SELECT id, area, dbnr, typ, address, hyst, logcmd, onmsg, offmsg, dimension, caption FROM iopoints WHERE client ='%d';" \
|
||||
%client)
|
||||
except:
|
||||
print ("couldn't get iopoints")
|
||||
raise Warning
|
||||
|
||||
return cursor.fetchall ()
|
||||
|
||||
|
||||
def getallmsglogs (self):
|
||||
"""
|
||||
returns all msglog entrys
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("SELECT m.id, c.client, i.caption, ms.msg, m.timestamp FROM msglog m \
|
||||
LEFT JOIN clients c ON (c.id = m.client) \
|
||||
LEFT JOIN iopoints i ON (i.id = m.iopoint) \
|
||||
LEFT JOIN messages ms ON (ms.id = m.msg)")
|
||||
except:
|
||||
print ("couldn't get msglog")
|
||||
raise Warning
|
||||
|
||||
return cursor.fetchall ()
|
||||
|
||||
|
||||
def getallvaluelogs (self):
|
||||
"""
|
||||
returns all valuelog entrys
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("SELECT v.id, c.client, i.caption, v.value, i.dimension, v.timestamp FROM valuelog v \
|
||||
LEFT JOIN clients c ON (c.id = v.client) \
|
||||
LEFT JOIN iopoints i ON (i.id = v.iopoint) \
|
||||
LEFT JOIN dimensions d ON (d.id = i.dimension)")
|
||||
except:
|
||||
print ("couldn't get valuelog entrys")
|
||||
raise Warning
|
||||
|
||||
return cursor.fetchall ()
|
||||
|
||||
|
||||
|
||||
def logmsg (self, client, iopoint, msg):
|
||||
"""
|
||||
save logmsg
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("INSERT INTO msglog VALUES (null, %d, %d, %d, current_timestamp)" %(client, iopoint, msg))
|
||||
except:
|
||||
print ("couldn't insert logmsg")
|
||||
raise Warning
|
||||
|
||||
|
||||
|
||||
def logvalue (self, client, iopoint, value):
|
||||
"""
|
||||
saves a valuelog
|
||||
"""
|
||||
|
||||
try:
|
||||
cursor = self.executesql ("INSERT INTO valuelog VALUES (null, %d, %d, %d, current_timestamp)" %(client, iopoint, value))
|
||||
except:
|
||||
print ("couldn't insert valuelog")
|
||||
raise Warning
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
conn = DB ("nodave.db3")
|
||||
print ("Value Logs")
|
||||
print ("-------------")
|
||||
for i in conn.getallvaluelogs ():
|
||||
print (i)
|
||||
|
||||
sys.exit(0)
|
||||
print ("Msg Logs")
|
||||
print ("-------------")
|
||||
for i in conn.getallmsglogs ():
|
||||
print (i)
|
||||
|
||||
10
Python/.svn/text-base/Makefile.svn-base
Normal file
10
Python/.svn/text-base/Makefile.svn-base
Normal file
@@ -0,0 +1,10 @@
|
||||
all: pydave.o pydave.so
|
||||
|
||||
pydave.o: pydave.c
|
||||
gcc -g -DNDEBUG -O2 -falign-loops=16 -save-temps -funroll-loops -funroll-all-loops -fno-strict-aliasing -Wall -Wstrict-prototypes -fPIC -c pydave.c -o pydave.o
|
||||
|
||||
pydave.so: pydave.o
|
||||
ld --shared pydave.o --shared ../nodave.o --shared ../openSocket.o -o pydave.so
|
||||
|
||||
clean:
|
||||
rm *.so *.o
|
||||
28
Python/.svn/text-base/davedefs.py.svn-base
Normal file
28
Python/.svn/text-base/davedefs.py.svn-base
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2000"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
daveAreas = {
|
||||
"P" : 0x80, #daveP
|
||||
"E" : 0x81, #daveInputs
|
||||
"A" : 0x82, #daveFlags
|
||||
"M" : 0x83, #daveDB Data Blocks
|
||||
"DB": 0x84, #daveDI Instance Data Blocs
|
||||
"DI": 0x85, #daveLocal !!! Untestet
|
||||
"C" : 0x1c, #daveCounter
|
||||
"T" : 0x1d #daveTimer
|
||||
}
|
||||
|
||||
daveTypes = {
|
||||
"BOOL" : 1,
|
||||
"BYTE" : 1,
|
||||
"WORD" : 2,
|
||||
"INT" : 2,
|
||||
"DWORD" : 4,
|
||||
"REAL" : 4,
|
||||
"DINT" : 4
|
||||
}
|
||||
|
||||
|
||||
195
Python/.svn/text-base/lamelle.py.svn-base
Normal file
195
Python/.svn/text-base/lamelle.py.svn-base
Normal file
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2009"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
from pydave import pydave
|
||||
from davedefs import *
|
||||
from ConfigParser import *
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
from select import select
|
||||
import sys
|
||||
import os
|
||||
from DB import DB
|
||||
|
||||
|
||||
#Enable Debug prints
|
||||
DEBUG = 0
|
||||
|
||||
def log_fifo (client, ioid, value):
|
||||
"""
|
||||
Log IO Value in a file (fifo)
|
||||
"""
|
||||
fifo = os.open('nodave.fifo', os.O_RDWR)
|
||||
#fifo = open ("nodave.fifo", "a")
|
||||
rdcons, wrcons, ccons = select ([], [fifo], [], 0.1)
|
||||
if fifo in wrcons:
|
||||
dt = datetime.now ()
|
||||
os.write (fifo, "%4d-%02d-%02d %02d:%02d:%02d.%06d; " %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond))
|
||||
os.write (fifo, "Client:%d; IOID:%d; Value:%d;\n" %(client, ioid, value))
|
||||
os.close (fifo)
|
||||
else:
|
||||
print ("FIFO is not writable")
|
||||
sys.exit (0)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
dbcon = DB ("nodave.db3")
|
||||
clients = []
|
||||
for _id, _name, _proto, _addr, _port, _mpi, _rack, _slot in [[5,'DrCutter', 'IBH_Link', '192.168.100.77', 1099, 2, 0, 0]]:
|
||||
print ("Found Client id %d '%s' with proto %s on address %s Port %d with MPI %d on Rack %d Slot %d" %(_id, _name, _proto, _addr, _port, _mpi, _rack, _slot))
|
||||
if _proto in ["ISO_TCP", "IBH_Link"]:
|
||||
a = pydave ()
|
||||
a.OpenSocket (_proto, _addr, _port, _mpi, _rack, _slot)
|
||||
clients.append ((_id, a, []))
|
||||
else:
|
||||
print ("Invalid Proto for Client")
|
||||
sys.exit (0)
|
||||
|
||||
for _clientid, _davecon, _vars in clients:
|
||||
#print "Client", _clientid, (_davecon.ReadBytes (daveAreas["M"], 0, 255, 1))
|
||||
print "Client", (_davecon.ReadBytes (daveAreas["DB"], 400, 0, 4))
|
||||
_iopoints = [] # dbcon.getiopointsclient (_clientid)
|
||||
_vars.append ({ "ID" : "Auto",
|
||||
"Typ" : "BOOL",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 0,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "Error",
|
||||
"Typ" : "BOOL",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 0,
|
||||
"BitAdd": 1,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "Offline",
|
||||
"Typ" : "BOOL",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 0,
|
||||
"BitAdd": 2,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "Program",
|
||||
"Typ" : "BYTE",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 1,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "Fertigteile",
|
||||
"Typ" : "DINT",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 2,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "Nio Cam1",
|
||||
"Typ" : "DINT",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 6,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "io Robby",
|
||||
"Typ" : "DINT",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 10,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "nio Einpressstation",
|
||||
"Typ" : "DINT",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 14,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "nio Cam3",
|
||||
"Typ" : "DINT",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 18,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "druck Stift 1",
|
||||
"Typ" : "REAL",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 22,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
_vars.append ({ "ID" : "druck Stift 3",
|
||||
"Typ" : "REAL",
|
||||
"Area" : "DB",
|
||||
"DBNr" : 400,
|
||||
"ByteAdd": 26,
|
||||
"BitAdd": 0,
|
||||
"Logcmd" : 1})
|
||||
|
||||
|
||||
while (1):
|
||||
print "Start"
|
||||
for _id, _davecon, _vars in clients:
|
||||
if DEBUG:
|
||||
print "Client", _id
|
||||
|
||||
_counter = 0
|
||||
vari = 0
|
||||
for _var in _vars:
|
||||
if (_counter == 0):
|
||||
_davecon.PrepareReadRequest ()
|
||||
|
||||
if (_var["Typ"] != "BOOL"):
|
||||
_davecon.AddVarToReadRequest (daveAreas [_var['Area']], _var['DBNr'], _var['ByteAdd'] , daveTypes[_var['Typ']])
|
||||
else:
|
||||
_davecon.AddBitVarToReadRequest (daveAreas [_var['Area']], _var['DBNr'], _var['ByteAdd'] * 8 + _var["BitAdd"] , 1)
|
||||
|
||||
_counter += 1
|
||||
if (_counter == 19) or (_var == _vars[-1]) :
|
||||
#Block requests to 19 Vals
|
||||
results = _davecon.ExecReadRequest ()
|
||||
if not results:
|
||||
break
|
||||
if len (results) != _counter:
|
||||
print ("Results other size than Variables")
|
||||
sys.exit (0)
|
||||
_counter = 0
|
||||
|
||||
for i in range (len (results)):
|
||||
if DEBUG:
|
||||
print " IO Point ", _vars[vari]
|
||||
|
||||
if (_vars [vari]["Logcmd"] & 1):
|
||||
#Print Value
|
||||
print " IO Point ", _vars[vari]['ID']
|
||||
if _vars [vari]["Typ"] == 'REAL':
|
||||
print " Value", _davecon.U32toREAL (results[i])
|
||||
else:
|
||||
print " Value", results[i]
|
||||
|
||||
# increment index of _vars
|
||||
vari +=1
|
||||
|
||||
if DEBUG:
|
||||
print "Vardata"
|
||||
for i in _vars:
|
||||
print i
|
||||
|
||||
sleep (4)
|
||||
|
||||
3
Python/.svn/text-base/nodave.cfg.svn-base
Normal file
3
Python/.svn/text-base/nodave.cfg.svn-base
Normal file
@@ -0,0 +1,3 @@
|
||||
[SPS1]
|
||||
ip = 192.168.100.72
|
||||
|
||||
BIN
Python/.svn/text-base/nodave.db3.svn-base
Normal file
BIN
Python/.svn/text-base/nodave.db3.svn-base
Normal file
Binary file not shown.
192
Python/.svn/text-base/nodave.py.svn-base
Normal file
192
Python/.svn/text-base/nodave.py.svn-base
Normal file
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2009"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
from pydave import pydave
|
||||
from davedefs import *
|
||||
from ConfigParser import *
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
from select import select
|
||||
import sys
|
||||
import os
|
||||
from DB import DB
|
||||
|
||||
|
||||
#Enable Debug prints
|
||||
DEBUG = 0
|
||||
|
||||
def log_fifo (client, ioid, value):
|
||||
"""
|
||||
Log IO Value in a file (fifo)
|
||||
"""
|
||||
fifo = os.open('nodave.fifo', os.O_RDWR)
|
||||
#fifo = open ("nodave.fifo", "a")
|
||||
rdcons, wrcons, ccons = select ([], [fifo], [], 0.1)
|
||||
if fifo in wrcons:
|
||||
dt = datetime.now ()
|
||||
os.write (fifo, "%4d-%02d-%02d %02d:%02d:%02d.%06d; " %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond))
|
||||
os.write (fifo, "Client:%d; IOID:%d; Value:%d;\n" %(client, ioid, value))
|
||||
os.close (fifo)
|
||||
else:
|
||||
print ("FIFO is not writable")
|
||||
sys.exit (0)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
dbcon = DB ("nodave.db3")
|
||||
clients = []
|
||||
for _id, _name, _proto, _addr, _mpi, _rack, _slot in dbcon.getallclients ():
|
||||
print ("Found Client id %d '%s' with proto %s on address %s with MPI %d on Rack %d Slot %d" %(_id, _name, _proto, _addr, _mpi, _rack, _slot))
|
||||
if _proto in ["ISO_TCP", "IBH_Link"]:
|
||||
a = pydave ()
|
||||
a.OpenSocket (_proto, _addr, 102, _mpi, _rack, _slot)
|
||||
clients.append ((_id, a, []))
|
||||
else:
|
||||
print ("Invalid Proto for Client")
|
||||
sys.exit (0)
|
||||
|
||||
for _clientid, _davecon, _vars in clients:
|
||||
#print "Client", _id, (_davecon.ReadBytes (daveAreas["M"], 0, 255, 1))
|
||||
#print "Client", (_davecon.ReadBytes (daveAreas["DB"], 10, 2, 4))
|
||||
_iopoints = dbcon.getiopointsclient (_clientid)
|
||||
for _ioid, _area, _dbnr, _typ, _address, _hyst, _logcmd, _onmsg, _offmsg, _dimension, _caption in _iopoints:
|
||||
print _ioid, _area, _dbnr, _typ, _address, _hyst, _logcmd, _onmsg, _offmsg, _dimension, _caption
|
||||
|
||||
if _area not in daveAreas:
|
||||
print ("Invalid Area %s of IO Id %d" %(_area, _ioid))
|
||||
sys.exit (0)
|
||||
|
||||
if (_area == "DB") and not (_dbnr > 0):
|
||||
print ("DB Nr of IO Id %d must be > 0" %_ioid)
|
||||
sys.exit (0)
|
||||
|
||||
if _typ not in daveTypes:
|
||||
print ("Var Type of Id %d invalid" %_ioid)
|
||||
sys.exit (0)
|
||||
|
||||
_byteaddress = 0
|
||||
_bitaddress = 0
|
||||
if '.' in _address:
|
||||
_address = _address.split ('.')
|
||||
try:
|
||||
_byteaddress = int (_address[0])
|
||||
_bitaddress = int (_address[1])
|
||||
except:
|
||||
print ("Error in Byte/Bitaddress conversion of IO Id %d" %_ioid)
|
||||
sys.exit (0)
|
||||
if (_typ != "BOOL"):
|
||||
print ("Error Bitadress used for nonBOOL Type in IO Id %d" %_ioid)
|
||||
_bitaddress = 0
|
||||
|
||||
else:
|
||||
try:
|
||||
_byteaddress = int (_address)
|
||||
except:
|
||||
print ("Error in Byteaddress conversion of IO Id %d" %_ioid)
|
||||
sys.exit (0)
|
||||
|
||||
if (_typ == "BOOL"):
|
||||
print ("Byteadress for BOOL Variable profided in IO id %d" %_ioid)
|
||||
sys.exit (0)
|
||||
|
||||
|
||||
_vars.append ({ "ID" : _ioid,
|
||||
"Typ" : _typ,
|
||||
"Area" : _area,
|
||||
"DBNr" : _dbnr,
|
||||
"ByteAdd": _byteaddress,
|
||||
"BitAdd": _bitaddress,
|
||||
"Hysterese" : _hyst,
|
||||
"Logcmd" : _logcmd,
|
||||
"OnMsg" : _onmsg,
|
||||
"OffMsg" : _offmsg,
|
||||
"Dimension" : _dimension,
|
||||
"Value" : -99999})
|
||||
|
||||
|
||||
|
||||
while (1):
|
||||
for _id, _davecon, _vars in clients:
|
||||
if DEBUG:
|
||||
print "Client", _id
|
||||
|
||||
_counter = 0
|
||||
vari = 0
|
||||
for _var in _vars:
|
||||
if (_counter == 0):
|
||||
_davecon.PrepareReadRequest ()
|
||||
|
||||
if (_var["Typ"] != "BOOL"):
|
||||
_davecon.AddVarToReadRequest (daveAreas [_var['Area']], _var['DBNr'], _var['ByteAdd'] , daveTypes[_var['Typ']])
|
||||
else:
|
||||
_davecon.AddBitVarToReadRequest (daveAreas [_var['Area']], _var['DBNr'], _var['ByteAdd'] * 8 + _var["BitAdd"] , 1)
|
||||
|
||||
_counter += 1
|
||||
if (_counter == 19) or (_var == _vars[-1]) :
|
||||
#Block requests to 19 Vals
|
||||
results = _davecon.ExecReadRequest ()
|
||||
if not results:
|
||||
break
|
||||
if len (results) != _counter:
|
||||
print ("Results other size than Variables")
|
||||
sys.exit (0)
|
||||
_counter = 0
|
||||
|
||||
for i in range (len (results)):
|
||||
if DEBUG:
|
||||
print " IO Point ", _vars[vari]
|
||||
|
||||
if (_vars [vari]["Logcmd"] & 1):
|
||||
#Print Value
|
||||
p=1
|
||||
#print " PrintlogClient", _id
|
||||
#print " IO Point ", _vars[vari]
|
||||
#print " New Value", results[i]
|
||||
|
||||
if (_vars [vari]["Logcmd"] & 2):
|
||||
#Log Value to Fifo
|
||||
log_fifo (_id, _vars [vari]["ID"], results[i])
|
||||
|
||||
# Just log to DB if Hysteresis was reached
|
||||
if abs (_vars [vari]["Value"] - results[i]) > _vars [vari]["Hysterese"]:
|
||||
if DEBUG:
|
||||
print " reached Hysteresis"
|
||||
|
||||
if (_vars [vari]["Logcmd"] & 4):
|
||||
#Log Message (intended for Bit Values)
|
||||
if DEBUG:
|
||||
print " MsgLog Cmd"
|
||||
if results [i] == 0:
|
||||
dbcon.logmsg (_id, _vars [vari]["ID"], _vars [vari]["OffMsg"])
|
||||
else:
|
||||
dbcon.logmsg (_id, _vars [vari]["ID"], _vars [vari]["OnMsg"])
|
||||
|
||||
if (_vars [vari]["Logcmd"] & 8):
|
||||
#Log Value
|
||||
if DEBUG:
|
||||
print " ValueLog Cmd"
|
||||
dbcon.logvalue (_id, _vars [vari]["ID"], results [i])
|
||||
|
||||
if (_vars [vari]["Logcmd"] & 16):
|
||||
#Store value
|
||||
if DEBUG:
|
||||
print " Valuestore Cmd"
|
||||
dbcon.setvalue (_id, _vars [vari]["ID"], results [i])
|
||||
|
||||
_vars [vari]["Value"] = results [i]
|
||||
|
||||
# increment index of _vars
|
||||
vari +=1
|
||||
|
||||
if DEBUG:
|
||||
print "Vardata"
|
||||
for i in _vars:
|
||||
print i
|
||||
|
||||
sleep (4)
|
||||
|
||||
542
Python/.svn/text-base/pydave.c.svn-base
Normal file
542
Python/.svn/text-base/pydave.c.svn-base
Normal file
@@ -0,0 +1,542 @@
|
||||
/*
|
||||
* Python Wrapper for llibnodave
|
||||
*
|
||||
* NOTE: !!!! Always use Prepare after a Byte Read
|
||||
*/
|
||||
#define LINUX
|
||||
|
||||
#include <python2.5/Python.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../nodave.h"
|
||||
#include "../nodavesimple.h"
|
||||
#include "../openSocket.h"
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// OpenSocket
|
||||
// Open Socket connection
|
||||
// "xxx.xxx.xxx.xxx" server - IP Address
|
||||
//---------------------------------------------------------
|
||||
static PyObject *
|
||||
ex_OpenSocket (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
_daveOSserialType fds;
|
||||
daveInterface *di;
|
||||
daveConnection *dconn;
|
||||
char *server;
|
||||
char *proto;
|
||||
int port, mpi, rack, slot, dproto, dspeed;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract Servername from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Ossiiii", &selfobj, &proto, &server, &port, &mpi, &rack, &slot)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
if (strcmp( proto, "ISO_TCP" ) == 0)
|
||||
{
|
||||
dproto = daveProtoISOTCP;
|
||||
}
|
||||
else if (strcmp( proto, "IBH_Link" ) == 0)
|
||||
{
|
||||
dproto = daveProtoMPI_IBH;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Invalid Proto.\n");
|
||||
return PyInt_FromLong (3);
|
||||
}
|
||||
|
||||
dspeed = daveSpeed187k;
|
||||
|
||||
fds.rfd = openSocket (port, server);
|
||||
fds.wfd = fds.rfd;
|
||||
|
||||
if (fds.rfd > 0)
|
||||
{
|
||||
di = daveNewInterface (fds, "IF1", 0, dproto, dspeed);
|
||||
if (0 == daveInitAdapter (di))
|
||||
{}
|
||||
daveSetTimeout (di, 5000000);
|
||||
dconn = daveNewConnection (di, mpi, rack, slot); // insert your rack and slot here
|
||||
|
||||
PyObject_SetAttrString (selfobj, "daveconaddr", PyCObject_FromVoidPtr (dconn, NULL));
|
||||
PyObject_SetAttrString (selfobj, "davesocket", PyCObject_FromVoidPtr (fds.rfd, NULL));
|
||||
if (0 == daveConnectPLC (dconn))
|
||||
{
|
||||
//printf ("Connected.\n");
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Couldn't connect to PLC.\n");
|
||||
return PyInt_FromLong (2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Couldn't open TCP port. \nPlease make sure a CP is connected and the IP address is ok. \n");
|
||||
return PyInt_FromLong (1);
|
||||
}
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect PLC
|
||||
*/
|
||||
static PyObject *
|
||||
ex_DisconnectPLC (PyObject *self, PyObject *args)
|
||||
{
|
||||
/*
|
||||
*/
|
||||
|
||||
PyObject *selfobj;
|
||||
daveConnection *dconn;
|
||||
int sock;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "O", &selfobj)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
sock = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "davesocket"));
|
||||
|
||||
daveDisconnectPLC (dconn);
|
||||
shutdown (sock, 2);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read Bytes
|
||||
*/
|
||||
static PyObject *
|
||||
ex_ReadBytes (PyObject *self, PyObject *args)
|
||||
{
|
||||
/*
|
||||
* Read len bytes from PLC memory area "area", data block DBnum.
|
||||
* Return the Number of bytes read.
|
||||
* If a buffer pointer is provided, data will be copied into this buffer.
|
||||
* If it's NULL you can get your data from the resultPointer in daveConnection long
|
||||
* as you do not send further requests.
|
||||
*
|
||||
* Area
|
||||
* daveP 0x80
|
||||
* daveInputs 0x81
|
||||
* daveOutputs 0x82
|
||||
* daveFlags 0x83 Merker
|
||||
* daveDB 0x84 data blocks
|
||||
* daveDI 0x85 instance data blocks
|
||||
* daveLocal 0x86 not tested
|
||||
* daveV 0x87 don't know what it is
|
||||
* daveCounter 28 S7 counters
|
||||
*
|
||||
|
||||
* DB
|
||||
* start
|
||||
* len
|
||||
*/
|
||||
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
int i, res;
|
||||
daveConnection *dconn;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iLen)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
|
||||
res = daveReadBytes (dconn, iArea, iDB, iStart, iLen, NULL);
|
||||
if (res == 0)
|
||||
{
|
||||
retval = PyList_New (iLen);
|
||||
for (i = 0; i < iLen; i++)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU8 (dconn)));
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("failed! (%d)\n", res);
|
||||
return PyInt_FromLong (res);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read Bits
|
||||
*/
|
||||
static PyObject *
|
||||
ex_ReadBits (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
daveConnection *dconn;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
int i, res;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iLen)))
|
||||
return NULL;
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
res = daveReadBits (dconn, iArea, iDB, iStart, iLen, NULL);
|
||||
if (res == 0)
|
||||
{
|
||||
retval = PyList_New (iLen);
|
||||
for (i = 0; i < iLen; i++)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU8 (dconn)));
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("failed! (%d)\n", res);
|
||||
return PyInt_FromLong (res);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Prepare Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_PrepareReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
daveConnection *dconn;
|
||||
PDU *pdu;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "O", &selfobj)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
|
||||
pdu = (PDU*) malloc (sizeof (PDU));
|
||||
PyObject_SetAttrString (selfobj, "pdu", PyCObject_FromVoidPtr (pdu, NULL));
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
|
||||
davePrepareReadRequest (dconn, pdu);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Add Bytes to Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_AddVarToReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PDU *pdu;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iLen)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
daveAddVarToReadRequest (pdu, iArea, iDB, iStart, iLen);
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add Bit to Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_AddBitVarToReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
int iArea, iDB, iStart, iBytePos;
|
||||
PDU *pdu;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iBytePos)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
daveAddBitVarToReadRequest (pdu, iArea, iDB, iStart, iBytePos);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Execute Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_ExecReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
daveResultSet rs;
|
||||
daveConnection *dconn;
|
||||
PDU *pdu;
|
||||
int i, rv, res, length;
|
||||
|
||||
|
||||
rs.numResults = 0;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "O", &selfobj)))
|
||||
return NULL;
|
||||
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
|
||||
|
||||
rv = daveExecReadRequest (dconn, pdu, &rs);
|
||||
if (rv !=0)
|
||||
{
|
||||
//printf ("daveExecReadRequest returns (%d)\n", rv);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
retval = PyList_New (rs.numResults);
|
||||
|
||||
if (rs.numResults == 0)
|
||||
{
|
||||
printf ("failed! no results\n");
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (1)
|
||||
{
|
||||
res = daveUseResult (dconn, &rs, i);
|
||||
if (res == 0)
|
||||
{
|
||||
length = rs.results[i].length;
|
||||
if (length == 1)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU8 (dconn)));
|
||||
else if (length == 2)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU16 (dconn)));
|
||||
else if (length == 4)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU32 (dconn)));
|
||||
else
|
||||
printf ("failed! size was (%d)\n", length);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
daveFreeResults (&rs);
|
||||
return retval;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write Bytes
|
||||
*/
|
||||
static PyObject *
|
||||
ex_WriteBytes (PyObject *self, PyObject *args)
|
||||
{
|
||||
/*
|
||||
* Write len bytes vrom Buvver to PLC memory area "area", data block DBnum.
|
||||
* If a buffer pointer is provided, data will be copied into this buffer.
|
||||
* If it's NULL you can get your data from the resultPointer in daveConnection long
|
||||
* as you do not send further requests.
|
||||
*
|
||||
* TODO Length check
|
||||
*
|
||||
* Area
|
||||
* daveP 0x80
|
||||
* daveInputs 0x81
|
||||
* daveOutputs 0x82
|
||||
* daveFlags 0x83 Merker
|
||||
* daveDB 0x84 data blocks
|
||||
* daveDI 0x85 instance data blocks
|
||||
* daveLocal 0x86 not tested
|
||||
* daveV 0x87 don't know what it is
|
||||
* daveCounter 28 S7 counters
|
||||
*
|
||||
|
||||
* DB
|
||||
* start
|
||||
* len
|
||||
*/
|
||||
|
||||
PyObject *selfobj;
|
||||
PyObject *values;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
int res;
|
||||
char * cvalues;
|
||||
daveConnection *dconn;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "OiiiiO", &selfobj, &iArea, &iDB, &iStart, &iLen, &values)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
cvalues = PyString_AsString (values);
|
||||
|
||||
res = daveWriteBytes (dconn, iArea, iDB, iStart, iLen, cvalues);
|
||||
if (res != 0)
|
||||
{
|
||||
printf ("failed! (%d)\n", res);
|
||||
return PyInt_FromLong (res);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* U32 to FloatRequest
|
||||
*/
|
||||
static PyObject *
|
||||
ex_U32toREAL (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
long value;
|
||||
uc * vp;
|
||||
union
|
||||
{
|
||||
float a;
|
||||
uc b[8];
|
||||
} f;
|
||||
|
||||
//Extract value
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Ol", &selfobj, &value)))
|
||||
return NULL;
|
||||
vp = (uc *) &value;
|
||||
f.b[0] = *(vp);
|
||||
vp++;
|
||||
f.b[1] = *(vp);
|
||||
vp++;
|
||||
f.b[2] = *(vp);
|
||||
vp++;
|
||||
f.b[3] = *(vp);
|
||||
retval = PyFloat_FromDouble (f.a);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static PyMethodDef pydaveMethods [] = {
|
||||
{"OpenSocket", ex_OpenSocket, METH_VARARGS, "Open Socket to PLC"},
|
||||
{"DisconnectPLC", ex_DisconnectPLC, METH_VARARGS, "Close Connection to PLC"},
|
||||
{"ReadBytes", ex_ReadBytes, METH_VARARGS, "Read Bytes from PLC"},
|
||||
//{"ReadManyBytes", ex_ReadManyBytes, METH_VARARGS, "Read Many Bytes from PLC"},
|
||||
{"ReadBits", ex_ReadBits, METH_VARARGS, "Read Bits from PLC"},
|
||||
{"WriteBytes", ex_WriteBytes, METH_VARARGS, "Write Bytes to PLC"},
|
||||
//{"WriteManyBytes", ex_WriteManyBytes, METH_VARARGS, "Write Bytes to PLC"},
|
||||
//{"WriteBit", ex_WriteBit, METH_VARARGS, "Write Bit to PLC"},
|
||||
//{"SetBit", ex_SetBit, METH_VARARGS, "Set Bit on PLC"},
|
||||
//{"ClrBit", ex_ClrBit, METH_VARARGS, "Clear Bit on PLC"},
|
||||
{"PrepareReadRequest", ex_PrepareReadRequest, METH_VARARGS, "Prepare Read Request"},
|
||||
{"AddVarToReadRequest", ex_AddVarToReadRequest, METH_VARARGS, "Add Variable to Read Request"},
|
||||
{"AddBitVarToReadRequest", ex_AddBitVarToReadRequest, METH_VARARGS, "Add Bit Variable to Read Request"},
|
||||
{"ExecReadRequest", ex_ExecReadRequest, METH_VARARGS, "Execute Read Request"},
|
||||
{"U32toREAL", ex_U32toREAL, METH_VARARGS, "Return Float"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PyMethodDef Modulemethods [] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PyMethodDef AttrMethods [] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
void initpydave (void)
|
||||
{
|
||||
PyMethodDef *def;
|
||||
|
||||
/*create a new module and class*/
|
||||
PyObject *module = Py_InitModule ("pydave", Modulemethods);
|
||||
PyObject *moduleDict = PyModule_GetDict (module);
|
||||
PyObject *classDict = PyDict_New ();
|
||||
PyObject *className = PyString_FromString ("pydave");
|
||||
|
||||
//PyObject *daveconaddr = Py_BuildValue ("i", 0);
|
||||
PyObject *daveconaddr = Py_None;
|
||||
PyDict_SetItemString (classDict, "daveconaddr", daveconaddr);
|
||||
|
||||
PyObject *pduPy = Py_None;
|
||||
//PDU *pdu = (PDU*) malloc (sizeof (PDU));
|
||||
//PyObject *pduPy = PyCObject_FromVoidPtr (pdu, NULL);
|
||||
PyDict_SetItemString (classDict, "pdu", pduPy);
|
||||
|
||||
for (def = AttrMethods; def->ml_name; def++)
|
||||
{
|
||||
PyObject *func = PyCFunction_New (def, NULL);
|
||||
PyDict_SetItemString (classDict, def->ml_name, func);
|
||||
Py_DECREF (func);
|
||||
}
|
||||
|
||||
PyObject *PyDaveClass = PyClass_New (NULL, classDict, className);
|
||||
PyDict_SetItemString (moduleDict, "pydave", PyDaveClass);
|
||||
Py_DECREF (classDict);
|
||||
Py_DECREF (className);
|
||||
Py_DECREF (PyDaveClass);
|
||||
|
||||
/* add methods to class */
|
||||
for (def = pydaveMethods; def->ml_name != NULL; def++)
|
||||
{
|
||||
PyObject *func = PyCFunction_New (def, NULL);
|
||||
PyObject *method = PyMethod_New (func, NULL, PyDaveClass);
|
||||
PyDict_SetItemString (classDict, def->ml_name, method);
|
||||
Py_DECREF (func);
|
||||
Py_DECREF (method);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
11
Python/Makefile
Normal file
11
Python/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
all: pydave.o pydave.so
|
||||
|
||||
pydave.o: pydave.c
|
||||
gcc -g -DNDEBUG -O2 -falign-loops=16 -save-temps -funroll-loops -funroll-all-loops -fno-strict-aliasing -Wall -Wstrict-prototypes -fPIC -c pydave.c -o pydave.o
|
||||
|
||||
pydave.so: pydave.o
|
||||
#ld --shared pydave.o --shared ../nodave.o --shared ../openSocket.o -o pydave.so
|
||||
ld -lpython2.7 --shared pydave.o --shared /usr/lib/libnodave.so -o pydave.so
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o *.i *.s *~
|
||||
28
Python/davedefs.py
Normal file
28
Python/davedefs.py
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2000"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
daveAreas = {
|
||||
"P" : 0x80, #daveP
|
||||
"E" : 0x81, #daveInputs
|
||||
"A" : 0x82, #daveFlags
|
||||
"M" : 0x83, #daveDB Data Blocks
|
||||
"DB": 0x84, #daveDI Instance Data Blocs
|
||||
"DI": 0x85, #daveLocal !!! Untestet
|
||||
"C" : 0x1c, #daveCounter
|
||||
"T" : 0x1d #daveTimer
|
||||
}
|
||||
|
||||
daveTypes = {
|
||||
"BOOL" : 1,
|
||||
"BYTE" : 1,
|
||||
"WORD" : 2,
|
||||
"INT" : 2,
|
||||
"DWORD" : 4,
|
||||
"REAL" : 4,
|
||||
"DINT" : 4
|
||||
}
|
||||
|
||||
|
||||
3
Python/nodave.cfg
Normal file
3
Python/nodave.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
[SPS1]
|
||||
ip = 192.168.100.72
|
||||
|
||||
BIN
Python/nodave.db3
Normal file
BIN
Python/nodave.db3
Normal file
Binary file not shown.
552
Python/pydave.c
Normal file
552
Python/pydave.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* Python Wrapper for llibnodave
|
||||
*
|
||||
* NOTE: !!!! Always use Prepare after a Byte Read
|
||||
*/
|
||||
#define LINUX
|
||||
|
||||
#include <python2.7/Python.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../nodave.h"
|
||||
#include "../nodavesimple.h"
|
||||
#include "../openSocket.h"
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// OpenSocket
|
||||
// Open Socket connection
|
||||
// "xxx.xxx.xxx.xxx" server - IP Address
|
||||
//---------------------------------------------------------
|
||||
static PyObject *
|
||||
ex_OpenSocket (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
_daveOSserialType fds;
|
||||
daveInterface *di;
|
||||
daveConnection *dconn;
|
||||
char *server;
|
||||
char *proto;
|
||||
int port, mpi, rack, slot, dproto, dspeed;
|
||||
int routingSubnetFirst, routingSubnetSecond, routingRack, routingSlot;
|
||||
int routingDestination;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract Servername from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Ossiiiiiiiii", &selfobj, &proto, &server, &port, &mpi, &rack, &slot, &routingSubnetFirst, &routingSubnetSecond, &routingRack, &routingSlot, &routingDestination)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
if (strcmp( proto, "ISO_TCP" ) == 0){
|
||||
dproto = daveProtoISOTCP;
|
||||
}
|
||||
else if (strcmp( proto, "IBH_Link" ) == 0){
|
||||
dproto = daveProtoMPI_IBH;
|
||||
}
|
||||
else{
|
||||
printf ("Invalid Proto.\n");
|
||||
return PyInt_FromLong (3);
|
||||
}
|
||||
|
||||
dspeed = daveSpeed187k;
|
||||
|
||||
fds.rfd = openSocket (port, server);
|
||||
fds.wfd = fds.rfd;
|
||||
|
||||
if (fds.rfd > 0) {
|
||||
di = daveNewInterface (fds, "IF1", 0, dproto, dspeed);
|
||||
if (0 == daveInitAdapter (di))
|
||||
{}
|
||||
daveSetTimeout (di, 5000000);
|
||||
if (routingSubnetFirst == 0) {
|
||||
dconn = daveNewConnection (di, mpi, rack, slot); // insert your rack and slot here
|
||||
}
|
||||
else {
|
||||
dconn = daveNewExtendedConnection (di, &mpi, 0, rack, slot, 1, routingSubnetFirst, routingSubnetSecond, routingRack, routingSlot, &routingDestination, 0, 1, 1);
|
||||
//daveNewExtendedConnection(daveInterface * di, void * Destination, int DestinationIsIP, int rack, int slot, int routing, int routingSubnetFirst, int routingSubnetSecond, int routingRack, int routingSlot, void * routingDestination, int routingDestinationIsIP, int ConnectionType, int routingConnectionType) {
|
||||
}
|
||||
|
||||
|
||||
PyObject_SetAttrString (selfobj, "daveconaddr", PyCObject_FromVoidPtr (dconn, NULL));
|
||||
PyObject_SetAttrString (selfobj, "davesocket", PyCObject_FromVoidPtr (fds.rfd, NULL));
|
||||
if (0 == daveConnectPLC (dconn))
|
||||
{
|
||||
//printf ("Connected.\n");
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Couldn't connect to PLC.\n");
|
||||
return PyInt_FromLong (2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Couldn't open TCP port. \nPlease make sure a CP is connected and the IP address is ok. \n");
|
||||
return PyInt_FromLong (1);
|
||||
}
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect PLC
|
||||
*/
|
||||
static PyObject *
|
||||
ex_DisconnectPLC (PyObject *self, PyObject *args)
|
||||
{
|
||||
/*
|
||||
*/
|
||||
|
||||
PyObject *selfobj;
|
||||
daveConnection *dconn;
|
||||
int sock;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "O", &selfobj)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
sock = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "davesocket"));
|
||||
|
||||
daveDisconnectPLC (dconn);
|
||||
shutdown (sock, 2);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read Bytes
|
||||
*/
|
||||
static PyObject *
|
||||
ex_ReadBytes (PyObject *self, PyObject *args)
|
||||
{
|
||||
/*
|
||||
* Read len bytes from PLC memory area "area", data block DBnum.
|
||||
* Return the Number of bytes read.
|
||||
* If a buffer pointer is provided, data will be copied into this buffer.
|
||||
* If it's NULL you can get your data from the resultPointer in daveConnection long
|
||||
* as you do not send further requests.
|
||||
*
|
||||
* Area
|
||||
* daveP 0x80
|
||||
* daveInputs 0x81
|
||||
* daveOutputs 0x82
|
||||
* daveFlags 0x83 Merker
|
||||
* daveDB 0x84 data blocks
|
||||
* daveDI 0x85 instance data blocks
|
||||
* daveLocal 0x86 not tested
|
||||
* daveV 0x87 don't know what it is
|
||||
* daveCounter 28 S7 counters
|
||||
*
|
||||
|
||||
* DB
|
||||
* start
|
||||
* len
|
||||
*/
|
||||
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
int i, res;
|
||||
daveConnection *dconn;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iLen)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
if (iLen > 222)
|
||||
{
|
||||
printf ("Readbytes Len exceeded PDU!\n");
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
res = daveReadBytes (dconn, iArea, iDB, iStart, iLen, NULL);
|
||||
if (res == 0)
|
||||
{
|
||||
retval = PyList_New (iLen);
|
||||
for (i = 0; i < iLen; i++)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU8 (dconn)));
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Readbytes failed! (%d)\n", res);
|
||||
return PyInt_FromLong (res);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read Bits
|
||||
*/
|
||||
static PyObject *
|
||||
ex_ReadBits (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
daveConnection *dconn;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
int i, res;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iLen)))
|
||||
return NULL;
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
res = daveReadBits (dconn, iArea, iDB, iStart, iLen, NULL);
|
||||
if (res == 0)
|
||||
{
|
||||
retval = PyList_New (iLen);
|
||||
for (i = 0; i < iLen; i++)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU8 (dconn)));
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("ReadBits failed! (%d)\n", res);
|
||||
return PyInt_FromLong (res);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Prepare Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_PrepareReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
daveConnection *dconn;
|
||||
PDU *pdu;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "O", &selfobj)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
|
||||
pdu = (PDU*) malloc (sizeof (PDU));
|
||||
PyObject_SetAttrString (selfobj, "pdu", PyCObject_FromVoidPtr (pdu, NULL));
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
|
||||
davePrepareReadRequest (dconn, pdu);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Add Bytes to Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_AddVarToReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PDU *pdu;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iLen)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
daveAddVarToReadRequest (pdu, iArea, iDB, iStart, iLen);
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add Bit to Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_AddBitVarToReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
int iArea, iDB, iStart, iBytePos;
|
||||
PDU *pdu;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Oiiii", &selfobj, &iArea, &iDB, &iStart, &iBytePos)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
daveAddBitVarToReadRequest (pdu, iArea, iDB, iStart, iBytePos);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Execute Read Request
|
||||
*/
|
||||
static PyObject *
|
||||
ex_ExecReadRequest (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
daveResultSet rs;
|
||||
daveConnection *dconn;
|
||||
PDU *pdu;
|
||||
int i, rv, res, length;
|
||||
|
||||
|
||||
rs.numResults = 0;
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "O", &selfobj)))
|
||||
return NULL;
|
||||
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
pdu = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "pdu"));
|
||||
|
||||
|
||||
rv = daveExecReadRequest (dconn, pdu, &rs);
|
||||
if (rv !=0)
|
||||
{
|
||||
//printf ("daveExecReadRequest returns (%d)\n", rv);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
retval = PyList_New (rs.numResults);
|
||||
|
||||
if (rs.numResults == 0)
|
||||
{
|
||||
printf ("Exec ReadReqest failed! no results\n");
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (1)
|
||||
{
|
||||
res = daveUseResult (dconn, &rs, i, NULL);
|
||||
if (res == 0)
|
||||
{
|
||||
length = rs.results[i].length;
|
||||
if (length == 1)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU8 (dconn)));
|
||||
else if (length == 2)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU16 (dconn)));
|
||||
else if (length == 4)
|
||||
PyList_SetItem (retval, i, PyInt_FromLong ((long) daveGetU32 (dconn)));
|
||||
else
|
||||
printf ("failed! size was (%d)\n", length);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
daveFreeResults (&rs);
|
||||
return retval;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write Bytes
|
||||
*/
|
||||
static PyObject *
|
||||
ex_WriteBytes (PyObject *self, PyObject *args)
|
||||
{
|
||||
/*
|
||||
* Write len bytes vrom Buvver to PLC memory area "area", data block DBnum.
|
||||
* If a buffer pointer is provided, data will be copied into this buffer.
|
||||
* If it's NULL you can get your data from the resultPointer in daveConnection long
|
||||
* as you do not send further requests.
|
||||
*
|
||||
* TODO Length check
|
||||
*
|
||||
* Area
|
||||
* daveP 0x80
|
||||
* daveInputs 0x81
|
||||
* daveOutputs 0x82
|
||||
* daveFlags 0x83 Merker
|
||||
* daveDB 0x84 data blocks
|
||||
* daveDI 0x85 instance data blocks
|
||||
* daveLocal 0x86 not tested
|
||||
* daveV 0x87 don't know what it is
|
||||
* daveCounter 28 S7 counters
|
||||
*
|
||||
|
||||
* DB
|
||||
* start
|
||||
* len
|
||||
*/
|
||||
|
||||
PyObject *selfobj;
|
||||
PyObject *values;
|
||||
int iArea, iDB, iStart, iLen;
|
||||
int res;
|
||||
char * cvalues;
|
||||
daveConnection *dconn;
|
||||
daveSetDebug (daveDebugPrintErrors);
|
||||
|
||||
//Extract area, db, start, len from Arguments
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "OiiiiO", &selfobj, &iArea, &iDB, &iStart, &iLen, &values)))
|
||||
return NULL;
|
||||
Py_DECREF (args);
|
||||
|
||||
dconn = PyCObject_AsVoidPtr (PyObject_GetAttrString (selfobj, "daveconaddr"));
|
||||
cvalues = PyString_AsString (values);
|
||||
|
||||
res = daveWriteBytes (dconn, iArea, iDB, iStart, iLen, cvalues);
|
||||
if (res != 0)
|
||||
{
|
||||
printf ("WriteBytes failed! (%d)\n", res);
|
||||
return PyInt_FromLong (res);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* U32 to FloatRequest
|
||||
*/
|
||||
static PyObject *
|
||||
ex_U32toREAL (PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *selfobj;
|
||||
PyObject *retval;
|
||||
long value;
|
||||
uc * vp;
|
||||
union
|
||||
{
|
||||
float a;
|
||||
uc b[8];
|
||||
} f;
|
||||
|
||||
//Extract value
|
||||
Py_INCREF (args);
|
||||
if (!(PyArg_ParseTuple (args, "Ol", &selfobj, &value)))
|
||||
return NULL;
|
||||
vp = (uc *) &value;
|
||||
f.b[0] = *(vp);
|
||||
vp++;
|
||||
f.b[1] = *(vp);
|
||||
vp++;
|
||||
f.b[2] = *(vp);
|
||||
vp++;
|
||||
f.b[3] = *(vp);
|
||||
retval = PyFloat_FromDouble (f.a);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static PyMethodDef pydaveMethods [] = {
|
||||
{"OpenSocket", ex_OpenSocket, METH_VARARGS, "Open Socket to PLC"},
|
||||
{"DisconnectPLC", ex_DisconnectPLC, METH_VARARGS, "Close Connection to PLC"},
|
||||
{"ReadBytes", ex_ReadBytes, METH_VARARGS, "Read Bytes from PLC"},
|
||||
//{"ReadManyBytes", ex_ReadManyBytes, METH_VARARGS, "Read Many Bytes from PLC"},
|
||||
{"ReadBits", ex_ReadBits, METH_VARARGS, "Read Bits from PLC"},
|
||||
{"WriteBytes", ex_WriteBytes, METH_VARARGS, "Write Bytes to PLC"},
|
||||
//{"WriteManyBytes", ex_WriteManyBytes, METH_VARARGS, "Write Bytes to PLC"},
|
||||
//{"WriteBit", ex_WriteBit, METH_VARARGS, "Write Bit to PLC"},
|
||||
//{"SetBit", ex_SetBit, METH_VARARGS, "Set Bit on PLC"},
|
||||
//{"ClrBit", ex_ClrBit, METH_VARARGS, "Clear Bit on PLC"},
|
||||
{"PrepareReadRequest", ex_PrepareReadRequest, METH_VARARGS, "Prepare Read Request"},
|
||||
{"AddVarToReadRequest", ex_AddVarToReadRequest, METH_VARARGS, "Add Variable to Read Request"},
|
||||
{"AddBitVarToReadRequest", ex_AddBitVarToReadRequest, METH_VARARGS, "Add Bit Variable to Read Request"},
|
||||
{"ExecReadRequest", ex_ExecReadRequest, METH_VARARGS, "Execute Read Request"},
|
||||
{"U32toREAL", ex_U32toREAL, METH_VARARGS, "Return Float"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PyMethodDef Modulemethods [] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PyMethodDef AttrMethods [] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
void initpydave (void)
|
||||
{
|
||||
PyMethodDef *def;
|
||||
|
||||
/*create a new module and class*/
|
||||
PyObject *module = Py_InitModule ("pydave", Modulemethods);
|
||||
PyObject *moduleDict = PyModule_GetDict (module);
|
||||
PyObject *classDict = PyDict_New ();
|
||||
PyObject *className = PyString_FromString ("pydave");
|
||||
|
||||
//PyObject *daveconaddr = Py_BuildValue ("i", 0);
|
||||
PyObject *daveconaddr = Py_None;
|
||||
PyDict_SetItemString (classDict, "daveconaddr", daveconaddr);
|
||||
|
||||
PyObject *pduPy = Py_None;
|
||||
//PDU *pdu = (PDU*) malloc (sizeof (PDU));
|
||||
//PyObject *pduPy = PyCObject_FromVoidPtr (pdu, NULL);
|
||||
PyDict_SetItemString (classDict, "pdu", pduPy);
|
||||
|
||||
for (def = AttrMethods; def->ml_name; def++)
|
||||
{
|
||||
PyObject *func = PyCFunction_New (def, NULL);
|
||||
PyDict_SetItemString (classDict, def->ml_name, func);
|
||||
Py_DECREF (func);
|
||||
}
|
||||
|
||||
PyObject *PyDaveClass = PyClass_New (NULL, classDict, className);
|
||||
PyDict_SetItemString (moduleDict, "pydave", PyDaveClass);
|
||||
Py_DECREF (classDict);
|
||||
Py_DECREF (className);
|
||||
Py_DECREF (PyDaveClass);
|
||||
|
||||
/* add methods to class */
|
||||
for (def = pydaveMethods; def->ml_name != NULL; def++)
|
||||
{
|
||||
PyObject *func = PyCFunction_New (def, NULL);
|
||||
PyObject *method = PyMethod_New (func, NULL, PyDaveClass);
|
||||
PyDict_SetItemString (classDict, def->ml_name, method);
|
||||
Py_DECREF (func);
|
||||
Py_DECREF (method);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
93
Python/testIBH.py
Executable file
93
Python/testIBH.py
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2009"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
from pydave import pydave
|
||||
from davedefs import *
|
||||
from ConfigParser import *
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
from select import select
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import signal
|
||||
import redis
|
||||
|
||||
#Enable Debug prints
|
||||
DEBUG = 0
|
||||
|
||||
|
||||
def on_term (signum, frame):
|
||||
sys.exit (1);
|
||||
def on_usr (signum, frame):
|
||||
pass;
|
||||
if __name__ == '__main__':
|
||||
signal.signal (signal.SIGTERM, on_term)
|
||||
signal.signal (signal.SIGUSR2, on_usr)
|
||||
signal.signal( signal.SIGUSR1, on_usr)
|
||||
INSTANZ= sys.argv[0];
|
||||
if len (sys.argv) > 2 and sys.argv[2] == '-init':
|
||||
sys.exit (0)
|
||||
if len (sys.argv) > 2 and sys.argv[2] == '-deinit' :
|
||||
if len(sys.argv) > 3 and sys.argv[3] == '-forced' :
|
||||
if len(sys.argv) > 4 :
|
||||
ListOfTerminatedInstances=string.split (sys.argv [4], ',')
|
||||
for inst in ListOfTerminatedInstances:
|
||||
# Cleanup
|
||||
|
||||
pass;
|
||||
sys.exit (0)
|
||||
r_server = redis.Redis ('176.9.41.147')
|
||||
#for _id, _name, _proto, _addr, _port, _mpi, _rack, _slot in [[5,'H6L2', 'ISO_TCP', '192.168.100.73', 102, 2, 0, 4]]:
|
||||
#for _id, _name, _proto, _addr, _port, _mpi, _rack, _slot in [[5,'H6L1', 'ISO_TCP', '192.168.100.73', 102, 3, 0, 4]]:
|
||||
clients = [
|
||||
[1,'Centrotherm', 'IBH_Link', '192.168.125.201', 1099, 2, 0, 4, 0, 0, 0, 0, 0],
|
||||
]
|
||||
conns = {}
|
||||
for client in clients:
|
||||
_id, _name, _proto, _addr, _port, _mpi, _rack, _slot, _rsid1, _rsid2, _rrack, _rslot, _rmpi = client
|
||||
print (_name)
|
||||
print ("========================================")
|
||||
print ("open connection")
|
||||
|
||||
#print ("Found Client id %d '%s' with proto %s on address %s Port %d with MPI %d on Rack %d Slot %d" %(_id, _name, _proto, _addr, _port, _mpi, _rack, _slot))
|
||||
if _proto in ["ISO_TCP","IBH_Link"]:
|
||||
conns [_id] = pydave ()
|
||||
conns [_id].OpenSocket (_proto, _addr, _port, _mpi, _rack, _slot, _rsid1, _rsid2, _rrack, _rslot, _rmpi)
|
||||
#routingSubnetFirst, routingSubnetSecond, routingRack, routingSlot
|
||||
else:
|
||||
print ("Invalid Proto for Client")
|
||||
sys.exit (0)
|
||||
|
||||
for client in clients:
|
||||
_id, _name, _proto, _addr, _port, _mpi, _rack, _slot, _rsid1, _rsid2, _rrack, _rslot, _rmpi = client
|
||||
print (_name)
|
||||
print ("========================================")
|
||||
nr = 1
|
||||
offset = 0
|
||||
blocksize = 220
|
||||
r_pipe = r_server.pipeline ()
|
||||
while nr < 300:
|
||||
val = conns [_id].ReadBytes (daveAreas["DB"], 2, offset, blocksize)
|
||||
for i in range (len (val) / 4):
|
||||
counter = (val [i * 4 + 0] << 8) + val [i * 4 + 1]
|
||||
print "%s Counter = %d" % (nr, counter)
|
||||
print "%s State = %d" % (nr, val [i * 4 + 2])
|
||||
print "%s Action = %d" % (nr, val [i * 4 + 3])
|
||||
r_pipe.set('Counter%03d' % nr, counter)
|
||||
r_pipe.set('State%03d' % nr, val [i * 4 + 2])
|
||||
r_pipe.set('Action%03d' % nr, val [i * 4 + 3])
|
||||
nr += 1
|
||||
offset += blocksize
|
||||
r_pipe.execute ()
|
||||
|
||||
|
||||
|
||||
|
||||
conns [_id].DisconnectPLC ()
|
||||
|
||||
|
||||
53
Python/testRedis.py
Executable file
53
Python/testRedis.py
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2009"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
from ConfigParser import *
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import signal
|
||||
import redis
|
||||
|
||||
#Enable Debug prints
|
||||
DEBUG = 0
|
||||
|
||||
|
||||
def on_term (signum, frame):
|
||||
sys.exit (1);
|
||||
def on_usr (signum, frame):
|
||||
pass;
|
||||
if __name__ == '__main__':
|
||||
signal.signal (signal.SIGTERM, on_term)
|
||||
signal.signal (signal.SIGUSR2, on_usr)
|
||||
signal.signal( signal.SIGUSR1, on_usr)
|
||||
INSTANZ= sys.argv[0];
|
||||
if len (sys.argv) > 2 and sys.argv[2] == '-init':
|
||||
sys.exit (0)
|
||||
if len (sys.argv) > 2 and sys.argv[2] == '-deinit' :
|
||||
if len(sys.argv) > 3 and sys.argv[3] == '-forced' :
|
||||
if len(sys.argv) > 4 :
|
||||
ListOfTerminatedInstances=string.split (sys.argv [4], ',')
|
||||
for inst in ListOfTerminatedInstances:
|
||||
# Cleanup
|
||||
|
||||
pass;
|
||||
sys.exit (0)
|
||||
r_server = redis.Redis ('176.9.41.147')
|
||||
r_pipe = r_server.pipeline ()
|
||||
for nr in range (1,500):
|
||||
r_pipe.get('Counter%03d' % nr)
|
||||
print "Counters", r_pipe.execute ()
|
||||
for nr in range (1,250):
|
||||
r_pipe.get('State%03d' % nr)
|
||||
print "States", r_pipe.execute ()
|
||||
for nr in range (1,250):
|
||||
r_pipe.get('Action%03d' % nr)
|
||||
print "States", r_pipe.execute ()
|
||||
|
||||
|
||||
77
Python/testdave-routed.py
Executable file
77
Python/testdave-routed.py
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
__author__ = "Michael Rest"
|
||||
__date__ = "1 June 2009"
|
||||
__email__ = "michi@rosstein.de"
|
||||
__version__ = "$Revision: 1.0 $"[11:-2]
|
||||
|
||||
from pydave import pydave
|
||||
from davedefs import *
|
||||
from ConfigParser import *
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
from select import select
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import signal
|
||||
|
||||
|
||||
#Enable Debug prints
|
||||
DEBUG = 0
|
||||
|
||||
|
||||
def on_term (signum, frame):
|
||||
sys.exit (1);
|
||||
def on_usr (signum, frame):
|
||||
pass;
|
||||
if __name__ == '__main__':
|
||||
signal.signal (signal.SIGTERM, on_term)
|
||||
signal.signal (signal.SIGUSR2, on_usr)
|
||||
signal.signal( signal.SIGUSR1, on_usr)
|
||||
INSTANZ= sys.argv[0];
|
||||
if len (sys.argv) > 2 and sys.argv[2] == '-init':
|
||||
sys.exit (0)
|
||||
if len (sys.argv) > 2 and sys.argv[2] == '-deinit' :
|
||||
if len(sys.argv) > 3 and sys.argv[3] == '-forced' :
|
||||
if len(sys.argv) > 4 :
|
||||
ListOfTerminatedInstances=string.split (sys.argv [4], ',')
|
||||
for inst in ListOfTerminatedInstances:
|
||||
# Cleanup
|
||||
|
||||
pass;
|
||||
sys.exit (0)
|
||||
#for _id, _name, _proto, _addr, _port, _mpi, _rack, _slot in [[5,'H6L2', 'ISO_TCP', '192.168.100.73', 102, 2, 0, 4]]:
|
||||
#for _id, _name, _proto, _addr, _port, _mpi, _rack, _slot in [[5,'H6L1', 'ISO_TCP', '192.168.100.73', 102, 3, 0, 4]]:
|
||||
clients = [
|
||||
[1,'H6L3', 'ISO_TCP', '192.168.100.73', 102, 3, 0, 4, 0, 0, 0, 0, 0],
|
||||
[2,'H6L1', 'ISO_TCP', '192.168.100.73', 102, 3, 0, 4, 53, 1, 0, 3, 11],
|
||||
[3,'H6L2', 'ISO_TCP', '192.168.100.73', 102, 3, 0, 4, 53, 1, 0, 3, 2],
|
||||
]
|
||||
for client in clients:
|
||||
_id, _name, _proto, _addr, _port, _mpi, _rack, _slot, _rsid1, _rsid2, _rrack, _rslot, _rmpi = client
|
||||
print (_name)
|
||||
print ("========================================")
|
||||
#print ("Found Client id %d '%s' with proto %s on address %s Port %d with MPI %d on Rack %d Slot %d" %(_id, _name, _proto, _addr, _port, _mpi, _rack, _slot))
|
||||
if _proto in ["ISO_TCP","IBH_Link"]:
|
||||
a = pydave ()
|
||||
a.OpenSocket (_proto, _addr, _port, _mpi, _rack, _slot, _rsid1, _rsid2, _rrack, _rslot, _rmpi)
|
||||
#routingSubnetFirst, routingSubnetSecond, routingRack, routingSlot
|
||||
temperature = 0
|
||||
for i in range (1, 15):
|
||||
offset = i * 12 + 60
|
||||
temp = a.ReadBytes (daveAreas["DB"], 157, offset, 2)
|
||||
temperature = (temp [0] << 8) + temp [1]
|
||||
print "Temperature%02d=%d" % (i, temperature)
|
||||
|
||||
offset = i * 15 + 155
|
||||
curr = a.ReadBytes (daveAreas["DB"], 150, offset, 2)
|
||||
current = (curr [0] << 8) + curr [1]
|
||||
print "Current%02d=%d" % (i, current)
|
||||
|
||||
a.DisconnectPLC ()
|
||||
|
||||
else:
|
||||
print ("Invalid Proto for Client")
|
||||
sys.exit (0)
|
||||
|
||||
97
README.compiling
Normal file
97
README.compiling
Normal file
@@ -0,0 +1,97 @@
|
||||
How to compile in different enviroments:
|
||||
|
||||
1. Linux on i386: Just type make. Type (as root) make install. This will:
|
||||
copy libnodave.so to /usr/local/lib
|
||||
copy nodave.h to /usr/local/include
|
||||
|
||||
2. Linux on ARM:
|
||||
Uncomment the line: #CFLAGS+=-DARM_FIX in Makefile
|
||||
For cross development, replace CC= and LD= with the appropriate paths to your ARM compiler
|
||||
and linker.
|
||||
Do make.
|
||||
Either do make install or copy libnodave.so to the target system.
|
||||
|
||||
3. Linux on MIPS:
|
||||
For cross development, replace CC= and LD= with the appropriate paths to your MIPS compiler
|
||||
and linker.
|
||||
Do make.
|
||||
Either do make install or copy libnodave.so to the target system.
|
||||
|
||||
4. Microsoft Visual C++
|
||||
Adjust the path to nmake in vcwinmake.bat.
|
||||
Adjust paths in MAKEFILE.VC to your installation.
|
||||
Run batch file vcwinmake.bat.
|
||||
|
||||
5. Borland Free Commandline Tools
|
||||
Adjust the path to make in winmake.bat.
|
||||
Adjust paths in MAKEFILE.MAK to your installation.
|
||||
Run batch file winmake.bat.
|
||||
|
||||
6. Microsoft Visual C++ on LINUX under Wine
|
||||
Adjust paths in MAKEFILE.VC.WINE to your installation.
|
||||
Run make -f MAKEFILE.VC.WINE. This will use GNU make to build everything.
|
||||
|
||||
7. Borland Free Commandline Tools on LINUX under Wine
|
||||
Adjust the path to make in winemake script.
|
||||
Adjust paths in MAKEFILE.MAK to your installation.
|
||||
Run script winemake
|
||||
|
||||
Hint: I use
|
||||
|
||||
make -f MAKEFILE.VC.WINE
|
||||
|
||||
on a Linux box to compile the windows stuff. While I TRY to keep the other makefiles up to date,
|
||||
this file is where you should look for compiler options and filenames and compare to your setup
|
||||
if you have difficulties to reproduce the same results.
|
||||
|
||||
from the FAQ:
|
||||
|
||||
Q: I try to compile my source code which includes nodave.h. Why do I get:
|
||||
"#error Fill in what you need for your OS or API" ?
|
||||
A: Libnodave has to use different functions to read byte data from serial ports or TCP/IP streams
|
||||
depending on the operating system. You have to specify which OS you compile for.
|
||||
Define BCCWIN for Windows and LINUX for Linux or other Unix style operating systems. I do
|
||||
that using -DBCCWIN or -DLINUX when I call the compilers out of a Makefile. If you use an IDE
|
||||
(integrated development environment), refer to the IDE's documentation to learn where to do
|
||||
this. If you can't find out, you can help yourself putting the #define into your code (which
|
||||
means your code will not be portable to other OS without modification). example:
|
||||
|
||||
...
|
||||
#define BCCWIN // if you work on windows
|
||||
#include nodave.h // or nodavesimple.h, but NEVER both
|
||||
#include setport.h // if your code works with serial connections
|
||||
#include openSocket.h // if your code works with TCP/IP
|
||||
...
|
||||
Q: I try to compile libnodave from source code. There are problems.
|
||||
A: - You do not need to compile libnodave yourself. You won't do it with other DLLs (windows)
|
||||
or .so (Linux shared libraries). Normally, you will link such libraries dynamically with
|
||||
your code.
|
||||
- Nevertheless, you have the sources and you may chose to recompile it, recompile only the
|
||||
parts you need, etcetera.
|
||||
- You should know that S7 uses Motorola (big endian, high byte first) byte order (endianness)
|
||||
while Intel processors use Intel (little endian, low byte first). On Intel and similar
|
||||
machines, libnodave has to convert multibyte values. This is done in daveGetS2(), daveGetU2(),
|
||||
daveGetFloat() and friends. The conversion code is only compiled in if you #define
|
||||
DAVE_LITTLE_ENDIAN. Otherwise, big endian is assumed.
|
||||
- Be aware that I do compile releases of libnodave using gcc (for Linux) and MSVC++
|
||||
(for windows). I use the script buildall to build Linux and Windows release versions and test
|
||||
programs on a Linux box. Buildall uses Linux make with MAKEFILE.VC.WINE to invoke the MSVC++
|
||||
compiler for windows versions. There is also a MAKEFILE.VC which should work on a windows
|
||||
system using nmake, but it may be out of date :-(. If in doubt about compiler options or
|
||||
source files involved, refer to MAKEFILE.VC.WINE!
|
||||
|
||||
Q: I want to compile libnodave for another OS. What adaptions shall I have to make?
|
||||
A: - I suppose your OS is 32 bit and your compiler treats int as 32 bit. If not, you are in
|
||||
trouble!
|
||||
- You need to provide functional replacements for setport.c or setportw.c and openSocket.c or
|
||||
openSocketw.c
|
||||
- nodave.h: You need to define a record _daveOSserialType containing members:
|
||||
rfd: a data type that can refer to a serial port or a TCP socket for read access
|
||||
wfd: a data type that can refer to a serial port or a TCP socket for write access
|
||||
- nodave.c: You need to code functions stdread() and stdwrite() to read and write a number of
|
||||
bytes from/to a serial port to/from a buffer.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
67
Readme.win
Normal file
67
Readme.win
Normal file
@@ -0,0 +1,67 @@
|
||||
To build for windows:
|
||||
While former versions where built with Borland's free commandline tools, the resulting .dll and
|
||||
.lib files are incompatible with MSVC. So, from this version on, MSVC is preferred compiler for
|
||||
Win32. You can still build the .dll with Borland tools. For instructions see below.
|
||||
|
||||
To build libnodave.dll with MSVC:
|
||||
1. Get and install MSVC. There is a freely available package from Microsoft containing only the
|
||||
compiler and linker. You need some windows header files also, which are available as part
|
||||
of the "Platform Software Development Kit (PSDK)". This PSDK contains also a make utility
|
||||
named nmake.
|
||||
2. Makefile is for LINUX. For Windows, you need the file MAKEFILE.VC
|
||||
Either remove the file Makefile or call make with -fMAKEFILE.VC.
|
||||
3. Running make with no target will build statically used versions of the test
|
||||
programs and libnodave.dll
|
||||
4. Running make with target "dynamic" builds dynamically linked versions of the test
|
||||
programs and libnodave.dll.
|
||||
5. If you have difficulties to rebuild libnodave.dll, e.g.:
|
||||
- you get more or less underscores
|
||||
- you get error messages when compiling
|
||||
- you get mangled names
|
||||
- you get error messages when linking
|
||||
- the recompiled .dll behaves different from the precompiled one
|
||||
Allways check MAKEFILE.VC.WINE. This is what I use do build the files I distribute. And
|
||||
besides all efforts to maintain other makefiles, I may forget to update them...
|
||||
|
||||
To build libnodave.dll with BorlandC:
|
||||
1. Get and install the free commandline tools from borland (www.borland.com).
|
||||
2. The Makefile is for LINUX. For Windows, you need the file MAKEFILE.MAK.
|
||||
Either remove the file Makefile or call make with -f MAKEFILE.MAK.
|
||||
3. Running make with no target will build statically linked versions of the test
|
||||
programs and libnodave.dll
|
||||
4. Running make with target "dynamic" builds dynamically linked versions of the test
|
||||
programs and libnodave.dll.
|
||||
|
||||
Using the .dll with C:
|
||||
You can import either nodave.h or nodavesimple.h. While it makes no difference for most
|
||||
applications, it is recommended to use nodave.h, because:
|
||||
- it gives you full access to all internal structures and routines in case you want to do
|
||||
something unforeseen.
|
||||
- it is most certainly up to date because the library itself is build with it.
|
||||
nodavesimple.h is merely there for people who want to interface with languages not yet
|
||||
supported to give them a guideline what they need to define.
|
||||
In any case you must make sure that the conditionals BCCWIN and DAVE_LITTLE_ENDIAN are defined
|
||||
at the moment the preprocessor enters into nodave.h. You can do this by one of these means:
|
||||
- specify -DBCCWIN -DDAVELITTLE_ENDIAN on the compiler's commandline (recommended)
|
||||
- put the lines #define BCCWIN, #define DAVE_LITTLE_ENDIAN before #include "nodave.h"
|
||||
|
||||
|
||||
Using the .dll with FreePascal or Delphi:
|
||||
use unit nodave in your program. nodave.pas corresponds to the .dll generated with MSVC. Should
|
||||
you want to recompile the .dll with BorlandC and then use it from Pascal, also recompile
|
||||
unit nodave from nodave.pas.borland. The difference is in the use of underscores in the names
|
||||
imported from the .dll.
|
||||
|
||||
Using the .dll with C#:
|
||||
There are C# versions of testMPI in the directory dot-net. There is also another README in that
|
||||
directory. The files have been compiled and found to work with MONO 1.0.5 under Win2k. MONO is
|
||||
an open source implementation of C# and the .NET framework.
|
||||
|
||||
Using the .dll with other languages:
|
||||
Some people found it very difficult to port the structures daveInterface and daveConnection to
|
||||
other languages, e.g. VB. In fact, this is not necessary for 99% of all possible applications.
|
||||
Member fields of these structure either never need to be accessed outside libnodave itself or
|
||||
they can be accessed using some newly added helper functions. So, regardless how complicate
|
||||
you think daveInterface is, all you need is a pointer to it.
|
||||
|
||||
|
||||
87
accepter.c
Normal file
87
accepter.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Part of multithreaded network servers. The servers MAIN thread is started by
|
||||
the main program. It starts in turn the ACCEPTER thread, which accepts a
|
||||
connection and passes the file descriptor to the MAIN thread. The server MAIN
|
||||
thread starts a PORT SERVER thread to handle the connection. Thus, the
|
||||
PORT SERVER thread is NOT a child of ACCEPTER, but a brother and SIGCHILD goes
|
||||
to the server MAIN. If it would go to ACCEPTER, which is blocked in the
|
||||
accept() system call, we would get "process interrupted in system call" and
|
||||
that's it. Maybe its different with pthread library..?
|
||||
|
||||
Part of Libnodave, a free communication libray for Siemens S7 300/400.
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2001..2005.
|
||||
|
||||
LIBNDAVE is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
LIBNODAVE is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
int port;
|
||||
} accepter_info;
|
||||
|
||||
void *accepter(void *arg)
|
||||
{
|
||||
int s;
|
||||
int newfd, pipefd;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr_in addr;
|
||||
int i;
|
||||
int opt;
|
||||
usleep(10000);
|
||||
pipefd = ((accepter_info *) arg)->fd;
|
||||
LOG2(ThisModule "Accepter : My pipe is:%d\n", pipefd);
|
||||
FLUSH;
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (errno != 0) {
|
||||
LOG2(ThisModule "Accepter : socket %s\n", strerror(errno));
|
||||
FLUSH;
|
||||
}
|
||||
LOG2(ThisModule "Accepter : port %d\n",
|
||||
((accepter_info *) arg)->port);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port =htons(((accepter_info *) arg)->port);
|
||||
// (((((accepter_info *) arg)->port) & 0xff) << 8) |
|
||||
// (((((accepter_info *) arg)->port) & 0xff00) >> 8);
|
||||
// LOG2(ThisModule"Accepter : port %d\n",addr.sin_port);
|
||||
inet_aton("0.0.0.0", &addr.sin_addr);
|
||||
opt = 1;
|
||||
i = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, 4);
|
||||
LOG2(ThisModule "Accepter : setsockopt %s\n", strerror(errno));
|
||||
addrlen = sizeof(addr);
|
||||
bind(s, (struct sockaddr *) & addr, addrlen);
|
||||
LOG2(ThisModule "Accepter : bind %s\n", strerror(errno));
|
||||
listen(s, 1);
|
||||
LOG2(ThisModule "Accepter : listen: %s\n", strerror(errno));
|
||||
while (1) {
|
||||
addrlen = sizeof(addr);
|
||||
LOG1(ThisModule "Accepter : before accept\n");
|
||||
newfd = (accept(s, (struct sockaddr *) & addr, &addrlen));
|
||||
LOG2(ThisModule "Accepter: after accept. New fd:%d\n", newfd);
|
||||
FLUSH;
|
||||
LOG3(ThisModule "Accepter: PID(%d) client:%s\n", getpid(),
|
||||
inet_ntoa(addr.sin_addr));
|
||||
FLUSH;
|
||||
write(pipefd, &newfd, sizeof(newfd));
|
||||
}
|
||||
shutdown(s, 2);
|
||||
LOG3(ThisModule "Accepter : %d shutdown done. Socket is: %d\n",
|
||||
getpid(), s);
|
||||
}
|
||||
|
||||
struct abstr {
|
||||
int fd;
|
||||
int mask;
|
||||
};
|
||||
181
benchmark.c
Normal file
181
benchmark.c
Normal file
@@ -0,0 +1,181 @@
|
||||
extern int seconds, thirds;
|
||||
void rBenchmark(daveConnection * dc, int bmArea) {
|
||||
int i,res,maxReadLen,areaNumber;
|
||||
double usec;
|
||||
PDU p;
|
||||
#ifdef UNIX_STYLE
|
||||
struct timeval t1, t2;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
clock_t t1, t2;
|
||||
#endif
|
||||
seconds=0;thirds=0;
|
||||
maxReadLen=dc->maxPDUlength-46;
|
||||
areaNumber=0;
|
||||
if(bmArea==daveDB) areaNumber=1;
|
||||
printf("Now going to do read benchmark with minimum block length of 1.\n");
|
||||
wait();
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t1, NULL);
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t1=clock();
|
||||
#endif
|
||||
for (i=1;i<101;i++) {
|
||||
daveReadBytes(dc, bmArea, areaNumber,0, 1, NULL);
|
||||
if (i%10==0) {
|
||||
printf("...%d",i);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t2, NULL);
|
||||
usec = 1e6 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec;
|
||||
usec/=1e6;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t2=clock();
|
||||
usec = 0.001*(t2 - t1);
|
||||
#endif
|
||||
printf(" 100 reads took %g secs. \n",usec);
|
||||
printf(" retries: 2nd %d 3rd %d\n",seconds, thirds);
|
||||
seconds=0;thirds=0;
|
||||
|
||||
printf("Now going to do read benchmark with shurely supported block length %d.\n",maxReadLen);
|
||||
// daveSetDebug(daveDebugAll);
|
||||
wait();
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t1, NULL);
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t1=clock();
|
||||
#endif
|
||||
for (i=1;i<101;i++) {
|
||||
daveReadBytes(dc, bmArea, areaNumber, 0, maxReadLen, NULL);
|
||||
if (i%10==0) {
|
||||
printf("...%d",i);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t2, NULL);
|
||||
usec = 1e6 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec;
|
||||
usec/=1e6;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t2=clock();
|
||||
usec = 0.001*(t2 - t1);
|
||||
#endif
|
||||
printf(" 100 reads took %g secs. \n",usec);
|
||||
printf(" retries: 2nd %d 3rd %d\n",seconds, thirds);
|
||||
wait();
|
||||
seconds=0;thirds=0;
|
||||
|
||||
printf("Now going to do read benchmark with 5 variables in a single request.\n");
|
||||
printf("running...\n");
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t1, NULL);
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t1=clock();
|
||||
#endif
|
||||
for (i=1;i<101;i++) {
|
||||
davePrepareReadRequest(dc, &p);
|
||||
daveAddVarToReadRequest(&p,daveInputs,0,0,6);
|
||||
daveAddVarToReadRequest(&p,daveFlags,0,0,6);
|
||||
daveAddVarToReadRequest(&p,daveFlags,0,6,6);
|
||||
daveAddVarToReadRequest(&p,bmArea,areaNumber,4,54);
|
||||
daveAddVarToReadRequest(&p,bmArea,areaNumber,4,4);
|
||||
res=daveExecReadRequest(dc, &p, NULL);
|
||||
if (res!=0) printf("\nerror %d=%s\n",res,daveStrerror(res));
|
||||
if (i%10==0) {
|
||||
printf("...%d",i);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t2, NULL);
|
||||
usec = 1e6 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec;
|
||||
usec/=1e6;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t2=clock();
|
||||
usec = 0.001*(t2 - t1);
|
||||
#endif
|
||||
printf(" 100 reads took %g secs.\n",usec);
|
||||
printf(" retries: 2nd %d 3rd %d\n",seconds, thirds);
|
||||
}
|
||||
|
||||
void wBenchmark(daveConnection * dc,int bmArea) {
|
||||
int i, c, areaNumber, maxWriteLen;
|
||||
double usec;
|
||||
#ifdef UNIX_STYLE
|
||||
struct timeval t1, t2;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
clock_t t1, t2;
|
||||
#endif
|
||||
maxWriteLen=dc->maxPDUlength-28;
|
||||
areaNumber=0;
|
||||
if(bmArea==daveDB) areaNumber=1;
|
||||
printf("Now going to do write benchmark with minimum block length of 1.\n");
|
||||
wait();
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t1, NULL);
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t1=clock();
|
||||
#endif
|
||||
for (i=1;i<101;i++) {
|
||||
daveWriteBytes(dc, bmArea, areaNumber,0,1,&c);
|
||||
if (i%10==0) {
|
||||
printf("...%d",i);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t2, NULL);
|
||||
usec = 1e6 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec;
|
||||
usec/=1e6;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t2=clock();
|
||||
usec = 0.001*(t2 - t1);
|
||||
#endif
|
||||
printf(" 100 writes took %g secs. \n",usec);
|
||||
|
||||
printf("Now going to do write benchmark with shurely supported block length %d.\n",maxWriteLen);
|
||||
wait();
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t1, NULL);
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t1=clock();
|
||||
#endif
|
||||
for (i=1;i<101;i++) {
|
||||
daveWriteBytes(dc, bmArea, areaNumber, 0, maxWriteLen, &c);
|
||||
if (i%10==0) {
|
||||
printf("...%d",i);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#ifdef UNIX_STYLE
|
||||
gettimeofday(&t2, NULL);
|
||||
usec = 1e6 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec;
|
||||
usec/=1e6;
|
||||
#endif
|
||||
#ifdef BCCWIN
|
||||
t2=clock();
|
||||
usec = 0.001*(t2 - t1);
|
||||
#endif
|
||||
printf(" 100 writes took %g secs. \n",usec);
|
||||
wait();
|
||||
}
|
||||
/*
|
||||
Changes:
|
||||
|
||||
03/18/2005 introduced bmArea parameter. S7-200 doesn't have enough Merkers/Flags for long
|
||||
block benchmarks. Must use V memory. This is like DB1 of S7-300/400, but a CPU
|
||||
may have a DB1 or not depending on program. So in case of 300/400 use Merker/Flag
|
||||
memory.
|
||||
*/
|
||||
BIN
contributions/LotTrack-103.zip
Executable file
BIN
contributions/LotTrack-103.zip
Executable file
Binary file not shown.
454
contributions/PowerBasic/Dave.bas
Executable file
454
contributions/PowerBasic/Dave.bas
Executable file
@@ -0,0 +1,454 @@
|
||||
#PBFORMS CREATED V1.51
|
||||
'--------------------------------------------------------------------------------
|
||||
' Dave.bas 4/08/06
|
||||
' Test of LibNoDave Step7 MPI communication with PBWin 8.01
|
||||
' credit for all the great code goes to:
|
||||
' (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005 '
|
||||
'
|
||||
' PBWin version writen by Bob Clarke RT Engineering Larvik Norway (rtc@rte.no)
|
||||
' some variable and function names have been changed to avoid conflicts with PBW keywords
|
||||
' all the errors in the translation are surely mine.
|
||||
'--------------------------------------------------------------------------------
|
||||
|
||||
#COMPILE EXE ' make an exe file
|
||||
#DIM ALL ' check all variables and parameters
|
||||
#COMPILER PBWIN 8.01 ' version used for test
|
||||
' PBForms 1.51
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
' ** Includes **
|
||||
'------------------------------------------------------------------------------
|
||||
#PBFORMS BEGIN INCLUDES
|
||||
#RESOURCE "Dave.pbr"
|
||||
#IF NOT %DEF(%WINAPI)
|
||||
#INCLUDE "WIN32API.INC"
|
||||
#ENDIF
|
||||
#PBFORMS END INCLUDES
|
||||
#IF NOT %DEF(%DAVE_INC)
|
||||
#INCLUDE "DAVE.INC"
|
||||
#ENDIF
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
' ** Constants **
|
||||
'------------------------------------------------------------------------------
|
||||
#PBFORMS BEGIN CONSTANTS
|
||||
%IDC_QUIT = 2
|
||||
%IDB_READ = 501
|
||||
%IDB_ADD = 502
|
||||
%IDB_Write = 503
|
||||
%IDC_Status = 601
|
||||
%IDC_TEXTBOX1 = 701
|
||||
%IDC_TEXTBOX2 = 702
|
||||
%IDC_TEXTBOX3 = 703
|
||||
%IDC_TEXTBOX4 = 704
|
||||
%IDD_DIALOG1 = 1001
|
||||
#PBFORMS END CONSTANTS
|
||||
'------------------------------------------------------------------------------
|
||||
' ** GLOBALS **
|
||||
'--------------------------------------------------------------------------------
|
||||
GLOBAL sDato AS STRING ' PC date
|
||||
GLOBAL sTid AS STRING ' PC time
|
||||
GLOBAL gMhDlg AS LONG ' window handle
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
' ** Declarations **
|
||||
'------------------------------------------------------------------------------
|
||||
DECLARE CALLBACK FUNCTION MainCallBackProc()
|
||||
DECLARE FUNCTION ShowMainDialog(BYVAL hParent AS DWORD) AS LONG
|
||||
DECLARE FUNCTION Init1() AS LONG
|
||||
DECLARE FUNCTION Init2() AS LONG
|
||||
DECLARE FUNCTION Initialize(BYREF ph AS LONG, BYREF di AS LONG, BYREF DC AS LONG) AS LONG
|
||||
DECLARE SUB GameOver(BYREF ph AS LONG, BYREF di AS LONG, BYREF DC AS LONG)
|
||||
DECLARE SUB ReadScreen()
|
||||
DECLARE SUB WriteScreen()
|
||||
DECLARE SUB ReadFromPLC()
|
||||
DECLARE SUB addvalue()
|
||||
DECLARE SUB writeToPLC()
|
||||
|
||||
#PBFORMS DECLARATIONS
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
' ** Main Application Entry Point **
|
||||
'------------------------------------------------------------------------------
|
||||
FUNCTION PBMAIN()
|
||||
DIM lRslt AS LOCAL LONG
|
||||
|
||||
Init1()
|
||||
ShowMainDialog %HWND_DESKTOP
|
||||
Init2()
|
||||
DIALOG SHOW MODAL gMhDlg, CALL MainCallBackProc TO lRslt
|
||||
|
||||
END FUNCTION
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
FUNCTION Init1() AS LONG
|
||||
' before show dialog
|
||||
|
||||
DIM localMPI AS GLOBAL INTEGER
|
||||
DIM plcMPI AS GLOBAL INTEGER
|
||||
DIM Rack AS GLOBAL INTEGER
|
||||
DIM Slot AS GLOBAL INTEGER
|
||||
|
||||
DIM ph AS GLOBAL LONG ' port handle
|
||||
DIM di AS GLOBAL LONG ' dave interface handle
|
||||
DIM DC AS GLOBAL LONG ' dave connection handle
|
||||
|
||||
DIM sBaud AS GLOBAL STRING
|
||||
DIM sPort AS GLOBAL STRING
|
||||
DIM sParity AS GLOBAL STRING
|
||||
DIM sPeer AS GLOBAL STRING
|
||||
DIM sAcspnt AS GLOBAL STRING
|
||||
|
||||
DIM sT AS GLOBAL STRING
|
||||
DIM ok AS GLOBAL LONG
|
||||
DIM v1 AS GLOBAL LONG
|
||||
DIM v2 AS GLOBAL LONG
|
||||
DIM v3 AS GLOBAL LONG
|
||||
DIM v4 AS GLOBAL SINGLE
|
||||
DIM v5 AS GLOBAL SINGLE
|
||||
|
||||
localMPI = 0
|
||||
plcMPI = 2
|
||||
sPort = "COM1"
|
||||
sBaud = "38400"
|
||||
sParity = "O"
|
||||
sPeer = "192.168.1.1"
|
||||
sAcspnt = "/S7ONLINE"
|
||||
|
||||
FUNCTION = 0
|
||||
END FUNCTION 'Init1
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
' ** CallBacks **
|
||||
'------------------------------------------------------------------------------
|
||||
CALLBACK FUNCTION MainCallBackProc()
|
||||
|
||||
SELECT CASE AS LONG CBMSG
|
||||
CASE %WM_INITDIALOG
|
||||
' Initialization handler
|
||||
CASE %WM_NCACTIVATE
|
||||
STATIC hWndSaveFocus AS DWORD
|
||||
IF ISFALSE CBWPARAM THEN
|
||||
' Save control focus
|
||||
hWndSaveFocus = GetFocus()
|
||||
ELSEIF hWndSaveFocus THEN
|
||||
' Restore control focus
|
||||
SetFocus(hWndSaveFocus)
|
||||
hWndSaveFocus = 0
|
||||
END IF
|
||||
CASE %WM_COMMAND
|
||||
' Process control notifications
|
||||
SELECT CASE AS LONG CBCTL
|
||||
CASE %IDC_TEXTBOX1 ' MD0 field
|
||||
IF CBCTLMSG = %EN_KILLFOCUS THEN
|
||||
SELECT CASE CBCTL
|
||||
CASE %IDC_TEXTBOX1
|
||||
' read display
|
||||
END SELECT 'CBCTL
|
||||
END IF 'CBCTLMSG = %EN_KILLFOCUS
|
||||
CASE %IDC_TEXTBOX2 ' MD4 field
|
||||
IF CBCTLMSG = %EN_KILLFOCUS THEN
|
||||
SELECT CASE CBCTL
|
||||
CASE %IDC_TEXTBOX2
|
||||
' read display
|
||||
END SELECT 'CBCTL
|
||||
END IF 'CBCTLMSG = %EN_KILLFOCUS
|
||||
CASE %IDC_TEXTBOX3 ' MD8 field
|
||||
IF CBCTLMSG = %EN_KILLFOCUS THEN
|
||||
SELECT CASE CBCTL
|
||||
CASE %IDC_TEXTBOX3
|
||||
' read display
|
||||
END SELECT 'CBCTL
|
||||
END IF 'CBCTLMSG = %EN_KILLFOCUS
|
||||
CASE %IDC_TEXTBOX4 ' MD12 field
|
||||
IF CBCTLMSG = %EN_KILLFOCUS THEN
|
||||
SELECT CASE CBCTL
|
||||
CASE %IDC_TEXTBOX4
|
||||
' read display
|
||||
END SELECT 'CBCTL
|
||||
END IF 'CBCTLMSG = %EN_KILLFOCUS
|
||||
CASE %IDB_READ ' Read button
|
||||
IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
|
||||
readFromPLC()
|
||||
END IF
|
||||
CASE %IDB_ADD ' Add button
|
||||
IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
|
||||
addvalue()
|
||||
END IF
|
||||
CASE %IDB_WRITE ' Write button
|
||||
IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
|
||||
writeToPLC()
|
||||
END IF
|
||||
CASE %IDC_QUIT ' Quit button
|
||||
IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
|
||||
CONTROL DISABLE gMhDlg, %IDC_QUIT
|
||||
CALL GameOver(ph, di, DC)
|
||||
DIALOG END CBHNDL
|
||||
END IF
|
||||
END SELECT
|
||||
END SELECT
|
||||
|
||||
END FUNCTION
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
'------------------------------------------------------------------------------
|
||||
' ** Dialogs **
|
||||
'------------------------------------------------------------------------------
|
||||
FUNCTION ShowMainDialog(BYVAL hParent AS DWORD) AS LONG
|
||||
DIM lRslt AS LOCAL LONG
|
||||
|
||||
#PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
|
||||
LOCAL hDlg AS DWORD
|
||||
|
||||
DIALOG NEW hParent, "LibNoDave", 70, 70, 261, 130, %WS_POPUP OR _
|
||||
%WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR _
|
||||
%WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
|
||||
%DS_SETFONT, %WS_EX_WINDOWEDGE OR %WS_EX_CONTROLPARENT OR _
|
||||
%WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
|
||||
CONTROL ADD BUTTON, hDlg, %IDC_QUIT, "QUIT", 200, 95, 30, 15
|
||||
CONTROL ADD BUTTON, hDlg, %IDB_READ, "Read Flags", 55, 70, 40, 15
|
||||
CONTROL ADD BUTTON, hDlg, %IDB_ADD, "Add 1", 110, 70, 40, 15
|
||||
CONTROL ADD BUTTON, hDlg, %IDB_Write, "Write Flags", 165, 70, 40, 15
|
||||
CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX1, "FD 0", 25, 40, 40, 15
|
||||
CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX2, "FD 4", 80, 40, 40, 15
|
||||
CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX3, "FD 8", 135, 40, 40, 15
|
||||
CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX4, "FD 12", 190, 40, 40, 15
|
||||
CONTROL ADD LABEL, hDlg, %IDC_Status, "Status", 25, 10, 205, 10, _
|
||||
%WS_CHILD OR %WS_VISIBLE OR %SS_CENTER, %WS_EX_LEFT OR _
|
||||
%WS_EX_LTRREADING
|
||||
CONTROL SET COLOR hDlg, %IDC_Status, %BLUE, -1
|
||||
#PBFORMS END DIALOG
|
||||
|
||||
|
||||
#PBFORMS BEGIN CLEANUP %IDD_DIALOG1
|
||||
#PBFORMS END CLEANUP
|
||||
' Save the handle for global access
|
||||
gMhDlg = hDlg
|
||||
|
||||
FUNCTION = lRslt
|
||||
END FUNCTION
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
FUNCTION Init2() AS LONG
|
||||
' after show dialog
|
||||
|
||||
Initialize(ph, di, DC)
|
||||
IF ok = %False THEN
|
||||
CONTROL DISABLE gMhDlg, %IDB_READ
|
||||
CONTROL DISABLE gMhDlg, %IDB_WRITE
|
||||
END IF 'ok
|
||||
FUNCTION = ok
|
||||
|
||||
END FUNCTION
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
' This initialization is used in all test programs. In a real program, where you would
|
||||
' want to read again and again, keep the dc and di until your program terminates.
|
||||
'
|
||||
FUNCTION Initialize(BYREF ph AS LONG, BYREF di AS LONG, BYREF DC AS LONG) AS LONG
|
||||
DIM lvar AS LOCAL LONG
|
||||
DIM lRslt AS LOCAL LONG
|
||||
|
||||
ok = %False ' no connection
|
||||
ph = 0 ' port handle
|
||||
di = 0 ' dave interface handle
|
||||
DC = 0 ' dave connection handle
|
||||
REM uncomment the daveSetDebug... LINE, SAVE your sheet
|
||||
REM run excel FROM dos BOX WITH: excel yoursheet >debugout.txt
|
||||
REM SEND me the file debugout.txt IF you have trouble.
|
||||
REM CALL daveSetDebug(daveDebugAll)
|
||||
ph = openPort(sPort, sBaud$, ASC(LEFT$(sParity$, 1)))
|
||||
' Alternatives:
|
||||
REM ph = openSocket(102, peer$) ' for ISO over TCP
|
||||
REM ph = openSocket(1099, peer$)' for IBH NetLink
|
||||
REM ph = openS7online(acspnt$) ' to use Siemes libraries for transport (s7online)
|
||||
IF (ph > 0) THEN
|
||||
sT = "port handle ok: " + STR$(ph)
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
di = daveNewInterface(ph, ph, "IF1", 0, %daveProtoMPI, %daveSpeed187k)
|
||||
' Alternatives:
|
||||
REM di = daveNewInterface(ph, ph, "IF1", 0, daveProtoPPI, daveSpeed187k)
|
||||
REM di = daveNewInterface(ph, ph, "IF1", 0, daveProtoMPI_IBH, daveSpeed187k)
|
||||
REM di = daveNewInterface(ph, ph, "IF1", 0, daveProtoISOTCP, daveSpeed187k)
|
||||
REM di = daveNewInterface(ph, ph, "IF1", 0, daveProtoS7online, daveSpeed187k)
|
||||
'
|
||||
'You can set longer timeout here, if you have a slow connection
|
||||
' Call daveSetTimeout(di, 500000)
|
||||
lRslt = daveInitAdapter(di)
|
||||
IF lRslt = 0 THEN
|
||||
sT = "result from initAdapter ok: " + STR$(lRslt)
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
'
|
||||
' with ISO over TCP, set correct values for rack and slot of the CPU
|
||||
'
|
||||
DC = daveNewConnection(di, plcMPI, Rack, Slot)
|
||||
lRslt = daveConnectPLC(DC)
|
||||
IF lRslt = 0 THEN
|
||||
sT = "PLC connection ok: "
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
ok = %True
|
||||
ELSE
|
||||
ok = %False
|
||||
sT = "Error No PLC connection: " + STR$(lRslt)
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
EXIT FUNCTION
|
||||
END IF 'lRslt = daveConnectPLC
|
||||
ELSE
|
||||
sT = "Error initAdapter: " + STR$(lRslt)
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
EXIT FUNCTION
|
||||
END IF 'lRslt = daveInitAdapter
|
||||
ELSE
|
||||
ok = %False
|
||||
sT = "Error port handle: " + STR$(ph)
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
END IF '(ph > 0)
|
||||
FUNCTION = ok
|
||||
END FUNCTION 'Initialize
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
' Disconnect from PLC, disconnect from Adapter, close the serial interface or TCP/IP socket
|
||||
SUB GameOver(BYREF ph AS LONG, BYREF di AS LONG, BYREF DC AS LONG)
|
||||
DIM lvar AS LOCAL LONG
|
||||
DIM lRslt AS LOCAL LONG
|
||||
|
||||
sT = "disconnecting from PLC"
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
IF DC <> 0 THEN
|
||||
lRslt = daveDisconnectPLC(DC)
|
||||
CALL daveFree(DC)
|
||||
DC = 0
|
||||
END IF
|
||||
IF di <> 0 THEN
|
||||
lRslt = daveDisconnectAdapter(di)
|
||||
CALL daveFree(di)
|
||||
di = 0
|
||||
END IF
|
||||
IF ph <> 0 THEN
|
||||
lRslt = closePort(ph)
|
||||
ph = 0
|
||||
END IF
|
||||
ok = %False
|
||||
|
||||
END SUB 'GameOver
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
' read values from textboxes
|
||||
SUB ReadScreen
|
||||
DIM txt AS LOCAL STRING
|
||||
|
||||
' read screen values
|
||||
CONTROL GET TEXT gMhdlg, %IDC_TEXTBOX1 TO txt$
|
||||
v1 = VAL(txt$)
|
||||
CONTROL GET TEXT gMhdlg, %IDC_TEXTBOX2 TO txt$
|
||||
v2 = VAL(txt$)
|
||||
CONTROL GET TEXT gMhdlg, %IDC_TEXTBOX3 TO txt$
|
||||
v3 = VAL(txt$)
|
||||
CONTROL GET TEXT gMhdlg, %IDC_TEXTBOX4 TO txt$
|
||||
v4 = VAL(txt$)
|
||||
|
||||
END SUB 'ReadScreen
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
' write values to textboxes
|
||||
SUB WriteScreen
|
||||
DIM txt AS LOCAL STRING
|
||||
|
||||
' write values to screen
|
||||
txt$ = FORMAT$(v1,"#####") 'show MD0
|
||||
CONTROL SET TEXT gMhDlg, %IDC_TEXTBOX1, txt$
|
||||
txt$ = FORMAT$(v2,"#####") 'show MD4
|
||||
CONTROL SET TEXT gMhDlg, %IDC_TEXTBOX2, txt$
|
||||
txt$ = FORMAT$(v3,"#####") 'show MD8
|
||||
CONTROL SET TEXT gMhDlg, %IDC_TEXTBOX3, txt$
|
||||
txt$ = FORMAT$(v4,"#####.##") 'show MD12
|
||||
CONTROL SET TEXT gMhDlg, %IDC_TEXTBOX4, txt$
|
||||
|
||||
END SUB 'WriteScreen
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
' read some values from FD0,FD4,FD8,FD12 (MD0,MD4,MD8,MD12 in german notation)
|
||||
' to read from data block 12, you would need to write:
|
||||
' daveReadBytes(dc, daveDB, 12, 0, 16, 0)
|
||||
SUB ReadFromPLC()
|
||||
DIM lRslt AS LOCAL LONG
|
||||
DIM e AS LOCAL STRING
|
||||
|
||||
IF ok = %True THEN
|
||||
sT = "Testing PLC read "
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
lRslt = daveReadBytes(DC, %daveFlags, 0, 0, 16, 0)
|
||||
IF lRslt = 0 THEN
|
||||
v1 = daveGetS32(DC) 'MD0(DINT)
|
||||
v2 = daveGetS32(DC) 'MD4(DINT)
|
||||
v3 = daveGetS32(DC) 'MD8(DINT)
|
||||
v4 = daveGetFloat(DC) 'MD12(REAL)
|
||||
v5 = daveGetFloatAt(DC, 12)
|
||||
WriteScreen()
|
||||
ELSE
|
||||
e$ = daveStrError(lRslt)
|
||||
sT = " error: " + STR$(lRslt) + e$
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
END IF
|
||||
END IF
|
||||
|
||||
END SUB 'ReadFromPLC
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
SUB addvalue()
|
||||
|
||||
sT = " add 1 "
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
ReadScreen()
|
||||
v1 = v1 +1
|
||||
v2 = v2 +2
|
||||
v3 = v3 +3
|
||||
v4 = v4 +1.1
|
||||
WriteScreen()
|
||||
|
||||
END SUB 'addvalue
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
' read values from textboxes and
|
||||
' write values to FD0,FD4,FD8,FD12 (MD0,MD4,MD8,MD12 in german notation)
|
||||
SUB writeToPLC()
|
||||
DIM buffer(1024) AS BYTE
|
||||
DIM lRslt AS LOCAL LONG
|
||||
DIM e AS LOCAL STRING
|
||||
|
||||
IF ok = %True THEN
|
||||
sT = "Testing PLC write "
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
ReadScreen()
|
||||
' Here we put thre DINTs and a REAL into the buffer. davePutXXX does the necessary conversions.
|
||||
' The resulting byte pattern in the buffer is the same you would get, when you watch the PLC
|
||||
' memory (FB0 .. FB15) as bytes
|
||||
'
|
||||
lRslt = davePut32(buffer(0), v1)
|
||||
lRslt = davePut32(buffer(4), v2)
|
||||
lRslt = davePut32(buffer(8), v3)
|
||||
lRslt = davePutFloat(buffer(12), v4)
|
||||
lRslt = daveWriteBytes(DC, %daveFlags, 0, 0, 16, buffer(0))
|
||||
IF lRslt <> 0 THEN
|
||||
e$ = daveStrError(lRslt)
|
||||
sT = " error: " + STR$(lRslt) + e$
|
||||
CONTROL SET TEXT gMhDlg, %IDC_STATUS, sT
|
||||
END IF
|
||||
END IF
|
||||
|
||||
END SUB 'writeToPLC()
|
||||
'-----------------------------------------------------------------------------------------------
|
||||
BIN
contributions/PowerBasic/Dave.exe
Executable file
BIN
contributions/PowerBasic/Dave.exe
Executable file
Binary file not shown.
735
contributions/PowerBasic/Dave.inc
Executable file
735
contributions/PowerBasic/Dave.inc
Executable file
@@ -0,0 +1,735 @@
|
||||
'--------------------------------------------------------------------------------
|
||||
' Dave.inc 4/08/06
|
||||
' Test of LibNoDave Step7 MPI communication with PBWin 8.01
|
||||
' credit for all the great code goes to:
|
||||
' (C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2005 '
|
||||
'
|
||||
' PBWin version writen by Bob Clarke RT Engineering Larvik Norway (rtc@rte.no)
|
||||
' some variable and function names have been changed to avoid conflicts with PBW keywords
|
||||
' all the errors in the translation are surely mine.
|
||||
'--------------------------------------------------------------------------------
|
||||
|
||||
'--------------------------------------------------------------------------------
|
||||
|
||||
#IF NOT %DEF(%WINAPI)
|
||||
#INCLUDE "WIN32API.INC"
|
||||
#ENDIF
|
||||
#IF NOT %DEF(%COMMCTRL_INC)
|
||||
#INCLUDE "COMMCTRL.INC"
|
||||
#ENDIF
|
||||
#IF NOT %DEF(%PBForms_INC)
|
||||
#INCLUDE "PBForms.INC"
|
||||
#ENDIF
|
||||
#IF NOT %DEF(%COMDLG32_INC)
|
||||
#INCLUDE "COMDLG32.INC"
|
||||
#ENDIF
|
||||
|
||||
#IF NOT %DEF(%Dave_INC)
|
||||
%DAVE_INC = 1
|
||||
|
||||
'--------------------------------------------------------------------------------
|
||||
' Declarations
|
||||
'--------------------------------------------------------------------------------
|
||||
' Set and read debug level:
|
||||
'
|
||||
DECLARE SUB daveSetDebug LIB "libnodave.dll" (BYVAL level AS LONG)
|
||||
DECLARE FUNCTION daveGetDebug LIB "libnodave.dll" () AS LONG
|
||||
'
|
||||
' You may wonder what sense it might make to set debug level, as you cannot see
|
||||
' messages when you opened excel or some VB application from Windows GUI.
|
||||
' You can invoke Excel from the console or from a batch file with:
|
||||
' <myPathToExcel>\Excel.Exe <MyPathToXLS-File>VBATest.XLS >ExcelOut
|
||||
' This will start Excel with VBATest.XLS and all debug messages (and a few from Excel itself)
|
||||
' go into the file ExcelOut.
|
||||
'
|
||||
' Error code to message string conversion:
|
||||
' Call this function to get an explanation for error codes returned by other functions.
|
||||
'
|
||||
'
|
||||
' The folowing doesn't work properly. A VB string is something different from a pointer to char:
|
||||
'
|
||||
' Declare Function daveStrerror Lib "libnodave.dll" Alias "daveStrerror" (ByVal en As Long) As String
|
||||
'
|
||||
DECLARE FUNCTION daveInternalStrerror LIB "libnodave.dll" ALIAS "daveStrerror" (BYVAL en AS LONG) AS LONG
|
||||
' So, I added another function to libnodave wich copies the text into a VB String.
|
||||
' This function is still not useful without some code araound it, so I call it "internal"
|
||||
DECLARE SUB daveStringCopy LIB "libnodave.dll" ALIAS "daveStringCopy" (BYVAL internalPointer AS LONG, BYVAL s AS STRING)
|
||||
'
|
||||
' Setup a new interface structure using a handle to an open port or socket:
|
||||
'
|
||||
DECLARE FUNCTION daveNewInterface LIB "libnodave.dll" ALIAS "daveNewInterface"(BYVAL fd1 AS LONG, BYVAL fd2 AS LONG, BYVAL sname AS STRING, BYVAL localMPI AS LONG, BYVAL protocol AS LONG, BYVAL speed AS LONG) AS LONG
|
||||
'
|
||||
' Setup a new connection structure using an initialized daveInterface and PLC's MPI address.
|
||||
' Note: The parameter di must have been obtained from daveNewinterface.
|
||||
'
|
||||
DECLARE FUNCTION daveNewConnection LIB "libnodave.dll" ALIAS "daveNewConnection" (BYVAL di AS LONG, BYVAL mpi AS LONG, BYVAL Rack AS LONG, BYVAL Slot AS LONG) AS LONG
|
||||
'
|
||||
' PDU handling:
|
||||
' PDU is the central structure present in S7 communication.
|
||||
' It is composed of a 10 or 12 byte header,a parameter block and a data block.
|
||||
' When reading or writing values, the data field is itself composed of a data
|
||||
' header followed by payload data
|
||||
'
|
||||
' retrieve the answer:
|
||||
' Note: The parameter dc must have been obtained from daveNewConnection.
|
||||
'
|
||||
DECLARE FUNCTION daveGetResponse LIB "libnodave.dll" ALIAS "daveGetResponse" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' send PDU to PLC
|
||||
' Note: The parameter dc must have been obtained from daveNewConnection,
|
||||
' The parameter pdu must have been obtained from daveNewPDU.
|
||||
'
|
||||
DECLARE FUNCTION daveSendMessage LIB "libnodave.dll" ALIAS "daveSendMessage" (BYVAL DC AS LONG, BYVAL pdu AS LONG) AS LONG
|
||||
'******
|
||||
'
|
||||
'Utilities:
|
||||
'
|
||||
'****
|
||||
'*
|
||||
' Hex dump PDU:
|
||||
'
|
||||
DECLARE SUB daveDumpPDU LIB "libnodave.dll" ALIAS "daveDumpPDU" (BYVAL pdu AS LONG)
|
||||
'
|
||||
' Hex dump. Write the name followed by len bytes written in hex and a newline:
|
||||
'
|
||||
DECLARE SUB daveDump LIB "libnodave.dll" ALIAS "daveDump" (BYVAL sname AS STRING, BYVAL pdu AS LONG, BYVAL length AS LONG)
|
||||
'
|
||||
' names for PLC objects. This is again the intenal function. Use the wrapper code below.
|
||||
'
|
||||
DECLARE FUNCTION daveInternalAreaName LIB "libnodave.dll" ALIAS "daveAreaName" (BYVAL en AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveInternalBlockName LIB "libnodave.dll" ALIAS "daveBlockName" (BYVAL en AS LONG) AS LONG
|
||||
'
|
||||
' swap functions. They change the byte order, if byte order on the computer differs from
|
||||
' PLC byte order:
|
||||
'
|
||||
DECLARE FUNCTION daveSwapIed_16 LIB "libnodave.dll" ALIAS "daveSwapIed_16" (BYVAL x AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveSwapIed_32 LIB "libnodave.dll" ALIAS "daveSwapIed_32" (BYVAL x AS LONG) AS LONG
|
||||
'
|
||||
' Data conversion convenience functions. The older set has been removed.
|
||||
' Newer conversion routines. As the terms WORD, INT, INTEGER etc have different meanings
|
||||
' for users of different programming languages and compilers, I choose to provide a new
|
||||
' set of conversion routines named according to the bit length of the value used. The 'U'
|
||||
' or 'S' stands for unsigned or signed.
|
||||
'
|
||||
'
|
||||
' Get a value from the position b points to. B is typically a pointer to a buffer that has
|
||||
' been filled with daveReadBytes:
|
||||
'
|
||||
DECLARE FUNCTION toPLCfloat LIB "libnodave.dll" ALIAS "toPLCfloat" (BYVAL f AS SINGLE) AS SINGLE
|
||||
DECLARE FUNCTION daveToPLCfloat LIB "libnodave.dll" ALIAS "daveToPLCfloat" (BYVAL f AS SINGLE) AS LONG
|
||||
'
|
||||
' Copy and convert value of 8,16,or 32 bit, signed or unsigned at position pos
|
||||
' from internal buffer:
|
||||
'
|
||||
DECLARE FUNCTION daveGetS8from LIB "libnodave.dll" ALIAS "daveGetS8from" (BYREF buffer AS BYTE) AS LONG
|
||||
DECLARE FUNCTION daveGetU8from LIB "libnodave.dll" ALIAS "daveGetU8from" (BYREF buffer AS BYTE) AS LONG
|
||||
DECLARE FUNCTION daveGetS16from LIB "libnodave.dll" ALIAS "daveGetS16from" (BYREF buffer AS BYTE) AS LONG
|
||||
DECLARE FUNCTION daveGetU16from LIB "libnodave.dll" ALIAS "daveGetU16from" (BYREF buffer AS BYTE) AS LONG
|
||||
DECLARE FUNCTION daveGetS32from LIB "libnodave.dll" ALIAS "daveGetS32from" (BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
' Is there an unsigned long? Or a longer integer than long? This doesn't work.
|
||||
' Declare Function daveGetU32from Lib "libnodave.dll" (ByRef buffer As Byte) As Long
|
||||
'
|
||||
DECLARE FUNCTION daveGetFloatfrom LIB "libnodave.dll" ALIAS "daveGetFloatfrom" (BYREF buffer AS BYTE) AS SINGLE
|
||||
'
|
||||
' Copy and convert a value of 8,16,or 32 bit, signed or unsigned from internal buffer. These
|
||||
' functions increment an internal buffer position. This buffer position is set to zero by
|
||||
' daveReadBytes, daveReadBits, daveReadSZL.
|
||||
'
|
||||
DECLARE FUNCTION daveGetS8 LIB "libnodave.dll" ALIAS "daveGetS8" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetU8 LIB "libnodave.dll" ALIAS "daveGetU8" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetS16 LIB "libnodave.dll" ALIAS "daveGetS16" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetU16 LIB "libnodave.dll" ALIAS "daveGetU16" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetS32 LIB "libnodave.dll" ALIAS "daveGetS32" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' Is there an unsigned long? Or a longer integer than long? This doesn't work.
|
||||
'Declare Function daveGetU32 Lib "libnodave.dll" (ByVal dc As Long) As Long
|
||||
DECLARE FUNCTION daveGetFloat LIB "libnodave.dll" ALIAS "daveGetFloat" (BYVAL DC AS LONG) AS SINGLE
|
||||
'
|
||||
' Read a value of 8,16,or 32 bit, signed or unsigned at position pos from internal buffer:
|
||||
'
|
||||
DECLARE FUNCTION daveGetS8At LIB "libnodave.dll" ALIAS "daveGetS8At" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetU8At LIB "libnodave.dll" ALIAS "daveGetU8At" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetS16At LIB "libnodave.dll" ALIAS "daveGetS16At" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetU16At LIB "libnodave.dll" ALIAS "daveGetU16At" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetS32At LIB "libnodave.dll" ALIAS "daveGetS32At" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS LONG
|
||||
'
|
||||
' Is there an unsigned long? Or a longer integer than long? This doesn't work.
|
||||
'Declare Function daveGetU32At Lib "libnodave.dll" (ByVal dc As Long, ByVal pos As Long) As Long
|
||||
DECLARE FUNCTION daveGetFloatAt LIB "libnodave.dll" ALIAS "daveGetFloatAt" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS SINGLE
|
||||
'
|
||||
' Copy and convert a value of 8,16,or 32 bit, signed or unsigned into a buffer. The buffer
|
||||
' is usually used by daveWriteBytes, daveWriteBits later.
|
||||
'
|
||||
DECLARE FUNCTION davePut8 LIB "libnodave.dll" ALIAS "davePut8" (BYREF buffer AS BYTE, BYVAL value AS LONG) AS LONG
|
||||
DECLARE FUNCTION davePut16 LIB "libnodave.dll" ALIAS "davePut16" (BYREF buffer AS BYTE, BYVAL value AS LONG) AS LONG
|
||||
DECLARE FUNCTION davePut32 LIB "libnodave.dll" ALIAS "davePut32" (BYREF buffer AS BYTE, BYVAL value AS LONG) AS LONG
|
||||
DECLARE FUNCTION davePutFloat LIB "libnodave.dll" ALIAS "davePutFloat" (BYREF buffer AS BYTE, BYVAL value AS SINGLE) AS LONG
|
||||
'
|
||||
' Copy and convert a value of 8,16,or 32 bit, signed or unsigned to position pos of a buffer.
|
||||
' The buffer is usually used by daveWriteBytes, daveWriteBits later.
|
||||
'
|
||||
DECLARE FUNCTION davePut8At LIB "libnodave.dll" ALIAS "davePut8At" (BYREF buffer AS BYTE, BYVAL POS AS LONG, BYVAL value AS LONG) AS LONG
|
||||
DECLARE FUNCTION davePut16At LIB "libnodave.dll" ALIAS "davePut16At" (BYREF buffer AS BYTE, BYVAL POS AS LONG, BYVAL value AS LONG) AS LONG
|
||||
DECLARE FUNCTION davePut32At LIB "libnodave.dll" ALIAS "davePut32At" (BYREF buffer AS BYTE, BYVAL POS AS LONG, BYVAL value AS LONG) AS LONG
|
||||
DECLARE FUNCTION davePutFloatAt LIB "libnodave.dll" ALIAS "davePutFloatAt" (BYREF buffer AS BYTE, BYVAL POS AS LONG, BYVAL value AS SINGLE) AS LONG
|
||||
'
|
||||
' Takes a timer value and converts it into seconds:
|
||||
'
|
||||
DECLARE FUNCTION daveGetSeconds LIB "libnodave.dll" ALIAS "daveGetSeconds" (BYVAL DC AS LONG) AS SINGLE
|
||||
DECLARE FUNCTION daveGetSecondsAt LIB "libnodave.dll" ALIAS "daveGetSecondsAt" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS SINGLE
|
||||
'
|
||||
' Takes a counter value and converts it to integer:
|
||||
'
|
||||
DECLARE FUNCTION daveGetCounterValue LIB "libnodave.dll" ALIAS "daveGetCounterValue" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveGetCounterValueAt LIB "libnodave.dll" ALIAS "daveGetCounterValueAt" (BYVAL DC AS LONG, BYVAL POS AS LONG) AS LONG
|
||||
'
|
||||
' Get the order code (MLFB number) from a PLC. Does NOT work with 200 family.
|
||||
'
|
||||
DECLARE FUNCTION daveGetOrderCode LIB "libnodave.dll" ALIAS "daveGetOrderCode" (BYVAL en AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
' Connect to a PLC.
|
||||
'
|
||||
DECLARE FUNCTION daveConnectPLC LIB "libnodave.dll" ALIAS "daveConnectPLC" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
'
|
||||
' Read a value or a block of values from PLC.
|
||||
'
|
||||
DECLARE FUNCTION daveReadBytes LIB "libnodave.dll" ALIAS "daveReadBytes" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYVAL buffer AS LONG) AS LONG
|
||||
'
|
||||
' Read a long block of values from PLC. Long means too long to transport in a single PDU.
|
||||
'
|
||||
DECLARE FUNCTION daveManyReadBytes LIB "libnodave.dll" ALIAS "daveManyReadBytes" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYVAL buffer AS LONG) AS LONG
|
||||
'
|
||||
' Write a value or a block of values to PLC.
|
||||
'
|
||||
DECLARE FUNCTION daveWriteBytes LIB "libnodave.dll" ALIAS "daveWriteBytes" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
' Write a long block of values to PLC. Long means too long to transport in a single PDU.
|
||||
'
|
||||
DECLARE FUNCTION daveWriteManyBytes LIB "libnodave.dll" ALIAS "daveWriteManyBytes" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
' Read a bit from PLC. numBytes must be exactly one with all PLCs tested.
|
||||
' Start is calculated as 8*byte number+bit number.
|
||||
'
|
||||
DECLARE FUNCTION daveReadBits LIB "libnodave.dll" ALIAS "daveReadBits" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYVAL buffer AS LONG) AS LONG
|
||||
'
|
||||
' Write a bit to PLC. numBytes must be exactly one with all PLCs tested.
|
||||
'
|
||||
DECLARE FUNCTION daveWriteBits LIB "libnodave.dll" ALIAS "daveWriteBits" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
' Set a bit in PLC to 1.
|
||||
'
|
||||
DECLARE FUNCTION daveSetBit LIB "libnodave.dll" ALIAS "daveSetBit" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL byteAddress AS LONG, BYVAL bitAddress AS LONG) AS LONG
|
||||
'
|
||||
' Set a bit in PLC to 0.
|
||||
'
|
||||
DECLARE FUNCTION daveClrBit LIB "libnodave.dll" ALIAS "daveClrBit" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL byteAddress AS LONG, BYVAL bitAddress AS LONG) AS LONG
|
||||
'
|
||||
' Read a diagnostic list (SZL) from PLC. Does NOT work with 200 family.
|
||||
'
|
||||
DECLARE FUNCTION daveReadSZL LIB "libnodave.dll" ALIAS "daveReadSZL" (BYVAL DC AS LONG, BYVAL ID AS LONG, BYVAL index AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
DECLARE FUNCTION daveListBlocksOfType LIB "libnodave.dll" ALIAS "daveListBlocksOfType" (BYVAL DC AS LONG, BYVAL typ AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
DECLARE FUNCTION daveListBlocks LIB "libnodave.dll" ALIAS "daveListBlocks" (BYVAL DC AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
DECLARE FUNCTION internalDaveGetBlockInfo LIB "libnodave.dll" ALIAS "daveGetBlockInfo" (BYVAL DC AS LONG, BYREF buffer AS BYTE, BYVAL ltype AS LONG, BYVAL number AS LONG) AS LONG
|
||||
'
|
||||
DECLARE FUNCTION daveGetProgramBlock LIB "libnodave.dll" ALIAS "daveGetProgramBlock" (BYVAL DC AS LONG, BYVAL blockType AS LONG, BYVAL number AS LONG, BYREF buffer AS BYTE, BYREF length AS LONG) AS LONG
|
||||
'
|
||||
' Start or Stop a PLC:
|
||||
'
|
||||
DECLARE FUNCTION daveStart LIB "libnodave.dll" ALIAS "daveStart" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveStop LIB "libnodave.dll" ALIAS "daveStop" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' Set outputs (digital or analog ones) of an S7-200 that is in stop mode:
|
||||
'
|
||||
DECLARE FUNCTION daveForce200 LIB "libnodave.dll" ALIAS "daveForce200" (BYVAL DC AS LONG, BYVAL area AS LONG, BYVAL start AS LONG, BYVAL value AS LONG) AS LONG
|
||||
'
|
||||
' Initialize a multivariable read request.
|
||||
' The parameter PDU must have been obtained from daveNew PDU:
|
||||
'
|
||||
DECLARE SUB davePrepareReadRequest LIB "libnodave.dll" ALIAS "davePrepareReadRequest" (BYVAL DC AS LONG, BYVAL pdu AS LONG)
|
||||
'
|
||||
' Add a new variable to a prepared request:
|
||||
'
|
||||
DECLARE SUB daveAddVarToReadRequest LIB "libnodave.dll" ALIAS "daveAddVarToReadRequest" (BYVAL pdu AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG)
|
||||
'
|
||||
' Executes the entire request:
|
||||
'
|
||||
DECLARE FUNCTION daveExecReadRequest LIB "libnodave.dll" ALIAS "daveExecReadRequest" (BYVAL DC AS LONG, BYVAL pdu AS LONG, BYVAL rs AS LONG) AS LONG
|
||||
'
|
||||
' Use the n-th result. This lets the functions daveGet<data type> work on that part of the
|
||||
' internal buffer that contains the n-th result:
|
||||
'
|
||||
DECLARE FUNCTION daveUseResult LIB "libnodave.dll" ALIAS "daveUseResult" (BYVAL DC AS LONG, BYVAL rs AS LONG, BYVAL resultNumber AS LONG) AS LONG
|
||||
'
|
||||
' Frees the memory occupied by single results in the result structure. After that, you can reuse
|
||||
' the resultSet in another call to daveExecReadRequest.
|
||||
'
|
||||
DECLARE SUB daveFreeResults LIB "libnodave.dll" ALIAS "daveFreeResults" (BYVAL rs AS LONG)
|
||||
'
|
||||
' Adds a new bit variable to a prepared request. As with daveReadBits, numBytes must be one for
|
||||
' all tested PLCs.
|
||||
'
|
||||
DECLARE SUB daveAddBitVarToReadRequest LIB "libnodave.dll" ALIAS "daveAddBitVarToReadRequest" (BYVAL pdu AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG)
|
||||
'
|
||||
' Initialize a multivariable write request.
|
||||
' The parameter PDU must have been obtained from daveNew PDU:
|
||||
'
|
||||
DECLARE SUB davePrepareWriteRequest LIB "libnodave.dll" ALIAS "davePrepareWriteRequest" (BYVAL DC AS LONG, BYVAL pdu AS LONG)
|
||||
'
|
||||
' Add a new variable to a prepared write request:
|
||||
'
|
||||
DECLARE SUB daveAddVarToWriteRequest LIB "libnodave.dll" ALIAS "daveAddVarToWriteRequest" (BYVAL pdu AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYREF buffer AS BYTE)
|
||||
'
|
||||
' Add a new bit variable to a prepared write request:
|
||||
'
|
||||
DECLARE SUB daveAddBitVarToWriteRequest LIB "libnodave.dll" ALIAS "daveAddBitVarToWriteRequest" (BYVAL pdu AS LONG, BYVAL area AS LONG, BYVAL areaNumber AS LONG, BYVAL start AS LONG, BYVAL numBytes AS LONG, BYREF buffer AS BYTE)
|
||||
'
|
||||
' Execute the entire write request:
|
||||
'
|
||||
DECLARE FUNCTION daveExecWriteRequest LIB "libnodave.dll" ALIAS "daveExecWriteRequest" (BYVAL DC AS LONG, BYVAL pdu AS LONG, BYVAL rs AS LONG) AS LONG
|
||||
'
|
||||
' Initialize an MPI Adapter or NetLink Ethernet MPI gateway.
|
||||
' While some protocols do not need this, I recommend to allways use it. It will do nothing if
|
||||
' the protocol doesn't need it. But you can change protocols without changing your program code.
|
||||
'
|
||||
DECLARE FUNCTION daveInitAdapter LIB "libnodave.dll" ALIAS "daveInitAdapter" (BYVAL di AS LONG) AS LONG
|
||||
'
|
||||
' Disconnect from a PLC. While some protocols do not need this, I recommend to allways use it.
|
||||
' It will do nothing if the protocol doesn't need it. But you can change protocols without
|
||||
' changing your program code.
|
||||
'
|
||||
DECLARE FUNCTION daveDisconnectPLC LIB "libnodave.dll" ALIAS "daveDisconnectPLC" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
'
|
||||
' Disconnect from an MPI Adapter or NetLink Ethernet MPI gateway.
|
||||
' While some protocols do not need this, I recommend to allways use it.
|
||||
' It will do nothing if the protocol doesn't need it. But you can change protocols without
|
||||
' changing your program code.
|
||||
'
|
||||
DECLARE FUNCTION daveDisconnectAdapter LIB "libnodave.dll" ALIAS "daveDisconnectAdapter" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
'
|
||||
' List nodes on an MPI or Profibus Network:
|
||||
'
|
||||
DECLARE FUNCTION daveListReachablePartners LIB "libnodave.dll" ALIAS "daveListReachablePartners" (BYVAL DC AS LONG, BYREF buffer AS BYTE) AS LONG
|
||||
'
|
||||
'
|
||||
' Set/change the timeout for an interface:
|
||||
'
|
||||
DECLARE SUB daveSetTimeout LIB "libnodave.dll" ALIAS "daveSetTimeout" (BYVAL di AS LONG, BYVAL maxTime AS LONG)
|
||||
'
|
||||
' Read the timeout setting for an interface:
|
||||
'
|
||||
DECLARE FUNCTION daveGetTimeout LIB "libnodave.dll" ALIAS "daveGetTimeout" (BYVAL di AS LONG) AS LONG
|
||||
'
|
||||
' Get the name of an interface. Do NOT use this, but the wrapper function defined below!
|
||||
'
|
||||
DECLARE FUNCTION daveInternalGetName LIB "libnodave.dll" ALIAS "daveGetName" (BYVAL en AS LONG) AS LONG
|
||||
'
|
||||
' Get the MPI address of a connection.
|
||||
'
|
||||
DECLARE FUNCTION daveGetMPIAdr LIB "libnodave.dll" ALIAS "daveGetMPIAdr" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' Get the length (in bytes) of the last data received on a connection.
|
||||
'
|
||||
DECLARE FUNCTION daveGetAnswLen LIB "libnodave.dll" ALIAS "daveGetAnswLen" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' Get the maximum length of a communication packet (PDU).
|
||||
' This value depends on your CPU and connection type. It is negociated in daveConnectPLC.
|
||||
' A simple read can read MaxPDULen-18 bytes.
|
||||
'
|
||||
DECLARE FUNCTION daveGetMaxPDULen LIB "libnodave.dll" ALIAS "daveGetMaxPDULen" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' Reserve memory for a resultSet and get a handle to it:
|
||||
'
|
||||
DECLARE FUNCTION daveNewResultSet LIB "libnodave.dll" ALIAS "daveNewResultSet"() AS LONG
|
||||
'
|
||||
' Destroy handles to daveInterface, daveConnections, PDUs and resultSets
|
||||
' Free the memory reserved for them.
|
||||
'
|
||||
DECLARE SUB daveFree LIB "libnodave.dll" ALIAS "daveFree" (BYVAL item AS LONG)
|
||||
'
|
||||
' Reserve memory for a PDU and get a handle to it:
|
||||
'
|
||||
DECLARE FUNCTION daveNewPDU LIB "libnodave.dll" ALIAS "daveNewPDU" () AS LONG
|
||||
'
|
||||
' Get the error code of the n-th single result in a result set:
|
||||
'
|
||||
DECLARE FUNCTION daveGetErrorOfResult LIB "libnodave.dll" ALIAS "daveGetErrorOfResult" (BYVAL resultSet AS LONG, BYVAL resultNumber AS LONG) AS LONG
|
||||
'
|
||||
DECLARE FUNCTION daveForceDisconnectIBH LIB "libnodave.dll" ALIAS "daveForceDisconnectIBH" (BYVAL di AS LONG, BYVAL src AS LONG, BYVAL dest AS LONG, BYVAL mpi AS LONG) AS LONG
|
||||
'
|
||||
' Helper functions to open serial ports and IP connections. You can use others if you want and
|
||||
' pass their results to daveNewInterface.
|
||||
'
|
||||
' Open a serial port using name, baud rate and parity. Everything else is set automatically:
|
||||
'
|
||||
DECLARE FUNCTION openPort LIB "libnodave.dll" ALIAS "setPort" (BYVAL sportname AS STRING, BYVAL sbaudrate AS STRING, BYVAL bparity AS BYTE) AS LONG
|
||||
'
|
||||
' Open a TCP/IP connection using port number (1099 for NetLink, 102 for ISO over TCP) and
|
||||
' IP address. You must use an IP address, NOT a hostname!
|
||||
'
|
||||
DECLARE FUNCTION openSocket LIB "libnodave.dll" ALIAS "openSocket" (BYVAL lport AS LONG, BYVAL peer AS STRING) AS LONG
|
||||
'
|
||||
' Open an access oint. This is a name in you can add in the "set Programmer/PLC interface" dialog.
|
||||
' To the access point, you can assign an interface like MPI adapter, CP511 etc.
|
||||
'
|
||||
DECLARE FUNCTION openS7online LIB "libnodave.dll" ALIAS "openS7online" (BYVAL peer AS STRING) AS LONG
|
||||
'
|
||||
' Close connections and serial ports opened with above functions:
|
||||
'
|
||||
DECLARE FUNCTION closePort LIB "libnodave.dll" ALIAS "closePort" (BYVAL fh AS LONG) AS LONG
|
||||
'
|
||||
' Close handle opende by opens7online:
|
||||
'
|
||||
DECLARE FUNCTION closeS7online LIB "libnodave.dll" ALIAS "closeS7online" (BYVAL fh AS LONG) AS LONG
|
||||
'
|
||||
' Read Clock time from PLC:
|
||||
'
|
||||
DECLARE FUNCTION daveReadPLCTime LIB "libnodave.dll" ALIAS "daveReadPLCTime" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' set clock to a value given by user
|
||||
'
|
||||
DECLARE FUNCTION daveSetPLCTime LIB "libnodave.dll" ALIAS "daveSetPLCTime" (BYVAL DC AS LONG, BYREF timestamp AS BYTE) AS LONG
|
||||
'
|
||||
' set clock to PC system clock:
|
||||
'
|
||||
DECLARE FUNCTION daveSetPLCTimeToSystime LIB "libnodave.dll" ALIAS "daveSetPLCTimeToSystime" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' BCD conversions:
|
||||
'
|
||||
DECLARE FUNCTION daveToBCD LIB "libnodave.dll" ALIAS "daveToBCD" (BYVAL DC AS LONG) AS LONG
|
||||
DECLARE FUNCTION daveFromBCD LIB "libnodave.dll" ALIAS "daveFromBCD" (BYVAL DC AS LONG) AS LONG
|
||||
'
|
||||
' Here comes the wrapper code for functions returning strings:
|
||||
'
|
||||
FUNCTION daveStrError(BYVAL code AS LONG) AS STRING
|
||||
DIM x AS LOCAL STRING
|
||||
DIM ip AS LOCAL LONG
|
||||
|
||||
x$ = STRING$(256, 0) ' create a string of sufficient capacity
|
||||
ip = daveInternalStrerror(code) ' have the text for code copied in
|
||||
CALL daveStringCopy(ip, x$) ' have the text for code copied in
|
||||
x$ = LEFT$(x$, INSTR(x$, CHR$(0)) - 1) ' adjust the length
|
||||
daveStrError = x$ ' and return result
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION daveAreaName(BYVAL code AS LONG) AS STRING
|
||||
DIM x AS LOCAL STRING
|
||||
DIM ip AS LOCAL LONG
|
||||
|
||||
x$ = STRING$(256, 0) ' create a string of sufficient capacity
|
||||
ip = daveInternalAreaName(code) ' have the text for code copied in
|
||||
CALL daveStringCopy(ip, x$) ' have the text for code copied in
|
||||
x$ = LEFT$(x$, INSTR(x$, CHR$(0)) - 1) ' adjust the length
|
||||
daveAreaName = x$ ' and return result
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION daveBlockName(BYVAL code AS LONG) AS STRING
|
||||
DIM x AS LOCAL STRING
|
||||
DIM ip AS LOCAL LONG
|
||||
|
||||
x$ = STRING$(256, 0) ' create a string of sufficient capacity
|
||||
ip = daveInternalBlockName(code) ' have the text for code copied in
|
||||
CALL daveStringCopy(ip, x$) ' have the text for code copied in
|
||||
x$ = LEFT$(x$, INSTR(x$, CHR$(0)) - 1) ' adjust the length
|
||||
daveBlockName = x$ ' and return result
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION daveGetName(BYVAL di AS LONG) AS STRING
|
||||
DIM x AS LOCAL STRING
|
||||
DIM ip AS LOCAL LONG
|
||||
|
||||
x$ = STRING$(256, 0) ' create a string of sufficient capacity
|
||||
ip = daveInternalGetName(di) ' have the text for code copied in
|
||||
CALL daveStringCopy(ip, x$) ' have the text for code copied in
|
||||
x$ = LEFT$(x$, INSTR(x$, CHR$(0)) - 1) ' adjust the length
|
||||
daveGetName = x$ ' and return result
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION daveGetBlockInfo(BYVAL di AS LONG) AS BYTE
|
||||
DIM x AS LOCAL STRING
|
||||
DIM ip AS LOCAL LONG
|
||||
|
||||
x$ = STRING$(256, 0) ' create a string of sufficient capacity
|
||||
ip = daveInternalGetName(di) ' have the text for code copied in
|
||||
CALL daveStringCopy(ip, x$) ' have the text for code copied in
|
||||
x$ = LEFT$(x$, INSTR(x$, CHR$(0)) - 1) ' adjust the length
|
||||
' daveGetName = x$ ' and return result
|
||||
'********** ???????????????? *********
|
||||
END FUNCTION
|
||||
|
||||
'*****************************************************
|
||||
' End of interface declarations and helper functions.
|
||||
'*****************************************************
|
||||
|
||||
|
||||
'--------------------------------------------------------------------------------
|
||||
' Constants
|
||||
'--------------------------------------------------------------------------------
|
||||
$ProgVers = "Ver 1.0 28/07/06" ' Program version
|
||||
%MOD_ALT = &H00000001 ' keyboard hooks
|
||||
%MOD_CONTROL = &H00000002
|
||||
%MOD_SHIFT = &H00000004
|
||||
%DLE = &H10
|
||||
%ETX = &H03
|
||||
%STX = &H02
|
||||
%SYN = &H16
|
||||
'--------------------------------------------------------------------------------
|
||||
|
||||
'--------------------------------------------------------------------------------
|
||||
' LibNoDave Constants
|
||||
'--------------------------------------------------------------------------------
|
||||
' Protocol types to be used with newInterface
|
||||
%daveProtoMPI = 0 ' MPI FOR S7 300/400
|
||||
%daveProtoMPI2 = 1 ' MPI FOR S7 300/400, "Andrew's version"
|
||||
%daveProtoPPI = 10 ' PPI FOR S7 200
|
||||
%daveProtoISOTCP = 122 ' ISO over TCP
|
||||
%daveProtoISOTCP243 = 123 ' ISO over TCP WITH CP243
|
||||
%daveProtoMPI_IBH = 223 ' MPI WITH IBH NetLink MPI TO ethernet gateway
|
||||
%daveProtoPPI_IBH = 224 ' PPI WITH IBH NetLink PPI TO ethernet gateway
|
||||
%daveProtoNLpro = 230 ' MPI WITH NetLink Pro MPI TO ethernet gateway
|
||||
%daveProtoUserTransport = 255 ' USER defined transport protocol
|
||||
' ProfiBus speed constants
|
||||
%daveSpeed9k = 0
|
||||
%daveSpeed19k = 1
|
||||
%daveSpeed187k = 2
|
||||
%daveSpeed500k = 3
|
||||
%daveSpeed1500k = 4
|
||||
%daveSpeed45k = 5
|
||||
%daveSpeed93k = 6
|
||||
' Some MPI function codes (yet unused ones may be incorrect)
|
||||
%daveFuncOpenS7Connection = &HF0
|
||||
%daveFuncRead = &H04
|
||||
%daveFuncWrite = &H05
|
||||
%daveFuncRequestDownload = &H1A
|
||||
%daveFuncDownloadBlock = &H1B
|
||||
%daveFuncDownloadEnded = &H1C
|
||||
%daveFuncStartUpload = &H1D
|
||||
%daveFuncUpload = &H1E
|
||||
%daveFuncEndUpload = &H1F
|
||||
#IF 0
|
||||
' S7 specific constants
|
||||
$daveBlockType_OB = "8"
|
||||
$daveBlockType_DB = "A"
|
||||
$daveBlockType_SDB = "B"
|
||||
$daveBlockType_FC = "C"
|
||||
$daveBlockType_SFC = "D"
|
||||
$daveBlockType_FB = "E"
|
||||
$daveBlockType_SFB = "F"
|
||||
' Use these constants for parameter "area" in daveReadBytes and daveWriteBytes
|
||||
$daveSysInfo = "3" ' System info OF 200 family
|
||||
$daveSysFlags = "5" ' System flags OF 200 family
|
||||
$daveAnaIn = "6" ' analog inputs OF 200 family
|
||||
$daveAnaOut = "7" ' analog outputs OF 200 family
|
||||
$daveP = "80"
|
||||
$daveInputs = "81" ' Peripheral DATA like PIW, PQW
|
||||
$daveOutputs = "82"
|
||||
$daveFlags = "83"
|
||||
$daveDB = "84" ' DATA blocks
|
||||
$daveDI = "85" ' NOT tested
|
||||
$daveLocal = "86" ' NOT tested
|
||||
$daveV = "87" ' don't know what it is
|
||||
$daveCounter = "28" ' don't know what it is
|
||||
$daveTimer = "29" ' don't know what it is
|
||||
#ENDIF
|
||||
%daveSysInfo = &H3 ' System info of 200 family
|
||||
%daveSysFlags = &H5 ' System flags of 200 family
|
||||
%daveAnaIn = &H6 ' analog inputs of 200 family
|
||||
%daveAnaOut = &H7 ' analog outputs of 200 family
|
||||
%daveP = &H80 ' direct access to peripheral adresses
|
||||
%daveInputs = &H81
|
||||
%daveOutputs = &H82
|
||||
%daveFlags = &H83
|
||||
%daveDB = &H84 ' data blocks
|
||||
%daveDI = &H85 ' instance data blocks
|
||||
%daveV = &H87 ' don't know what it is
|
||||
%daveCounter = 28 ' S7 counters
|
||||
%daveTimer = 29 ' S7 timers
|
||||
%daveCounter200 = 30 ' IEC counters (200 family)
|
||||
%daveTimer200 = 31 ' IEC timers (200 family)
|
||||
'
|
||||
%daveOrderCodeSize = 21 ' Length of order code (MLFB number)
|
||||
|
||||
' Library specific Result codes
|
||||
' Generally, 0 means ok,
|
||||
' >0 are results (also errors) reported by the PLC
|
||||
' <0 means error reported by library code.
|
||||
%daveResOK = 0 ' means ALL ok
|
||||
' CPU tells it does not support to read a bit block with a length other than 1 bit
|
||||
%daveResMultipleBitsNotSupported = 6
|
||||
' means a a piece of data is not available in the CPU, e.g.
|
||||
' when trying TO READ a non existing DB OR BIT block OF length<>1
|
||||
%daveResItemNotAvailable200 = 3
|
||||
' This code seems to be specific to 200 family
|
||||
' means a a piece of data is not available in the CPU, e.g.
|
||||
' when trying TO READ a non existing DB
|
||||
%daveResItemNotAvailable = 10
|
||||
' means the data address is beyond the CPUs address range
|
||||
%daveAddressOutOfRange = 5
|
||||
%daveResCannotEvaluatePDU = -123
|
||||
%daveResCPUNoData = -124
|
||||
%daveUnknownError = -125
|
||||
%daveEmptyResultError = -126
|
||||
%daveEmptyResultSetError = -127
|
||||
|
||||
' Max number of bytes in a single message.
|
||||
' An upper limit for MPI over serial is:
|
||||
' 8 transport header
|
||||
' +2 240 max PDU len 2 if every character were a DLE
|
||||
' +3 DLE,ETX and BCC
|
||||
' = 491
|
||||
|
||||
' Later I saw some programs offering up to 960 bytes in PDU size negotiation
|
||||
|
||||
' Max number of bytes in a single message.
|
||||
' An upper limit for MPI over serial is:
|
||||
' 8 transport header
|
||||
' +2 960 max PDU len 2 if every character were a DLE
|
||||
' +3 DLE,ETX and BCC
|
||||
' = 1931
|
||||
|
||||
' For now, we take the rounded max of all this to determine our buffer size. This is ok
|
||||
' for PC systems, where one k less or more doesn't matter.
|
||||
%daveMaxRawLen = 2048
|
||||
|
||||
' Some definitions for debugging
|
||||
$daveDebugRawRead = "01" ' SHOW the SINGLE bytes received
|
||||
$daveDebugSpecialChars = "02" ' SHOW when special chars are READ
|
||||
$daveDebugRawWrite = "04" ' SHOW the SINGLE bytes written
|
||||
$daveDebugListReachables = "08" ' SHOW the steps when determine devices IN MPI net
|
||||
$daveDebugInitAdapter = "10" ' SHOW the steps when Initilizing the MPI adapter
|
||||
$daveDebugConnect = "20" ' SHOW the steps when connecting a PLC
|
||||
$daveDebugPacket = "40"
|
||||
$daveDebugByte = "80"
|
||||
$daveDebugCompare = "100"
|
||||
$daveDebugExchange = "200"
|
||||
$daveDebugPDU = "400" ' debug PDU handling
|
||||
$daveDebugUpload = "800" ' debug PDU loading program blocks FROM PLC
|
||||
$daveDebugMPI = "1000"
|
||||
$daveDebugPrintErrors = "2000" ' PRINT ERROR messages
|
||||
$daveDebugPassive = "4000"
|
||||
$daveDebugErrorReporting = "8000"
|
||||
$daveDebugOpen = "10000"
|
||||
$daveDebugAll = "1FFFF"
|
||||
$LibName = "libnodave.dll" ' WIN32
|
||||
|
||||
|
||||
'--------------------------------------------------------------------------------
|
||||
' Data structures
|
||||
'--------------------------------------------------------------------------------
|
||||
' WIN32
|
||||
TYPE typDaveOSserial BYTE
|
||||
rfd AS DWORD
|
||||
wfd AS DWORD
|
||||
END TYPE
|
||||
|
||||
' Helper struct to manage PDUs. This is NOT the part of the packet I would call PDU, but
|
||||
' a set of pointers that ease access to the "parts" of a PDU.
|
||||
' pointer to start of PDU (PDU header)
|
||||
' pointer to start of parameters inside PDU
|
||||
' pointer to start of data inside PDU
|
||||
' pointer to start of data inside PDU
|
||||
' header length
|
||||
' parameter length
|
||||
' data length
|
||||
' user or result data length
|
||||
TYPE typPDU BYTE
|
||||
pheader AS BYTE POINTER
|
||||
pparam AS BYTE POINTER
|
||||
pDATA AS BYTE POINTER
|
||||
udata AS BYTE POINTER
|
||||
hlen AS LONG
|
||||
plen AS LONG
|
||||
dlen AS LONG
|
||||
udlen AS LONG
|
||||
END TYPE
|
||||
|
||||
' Definitions of prototypes for the protocol specific functions. The library "switches"
|
||||
' protocol by setting pointers to the protol specific implementations.
|
||||
' This groups an interface together with some information about it's properties
|
||||
' in the library's context.
|
||||
' some handle for the serial interface
|
||||
' a counter used when multiple PLCs are accessed via
|
||||
' the same serial interface and adapter.
|
||||
' the adapter's MPI address
|
||||
' just a name that can be used in programs dealing with multiple
|
||||
' daveInterfaces
|
||||
' Timeout in microseconds used in transort.
|
||||
' The kind of transport protocol used on this interface.
|
||||
' The MPI or Profibus speed
|
||||
' position of some packet number that has to be repeated in ackknowledges
|
||||
' pointers to the protocol
|
||||
' specific implementations
|
||||
' of these functions
|
||||
TYPE typMPIheader BYTE
|
||||
src_conn AS BYTE
|
||||
dst_conn AS BYTE
|
||||
MPI AS BYTE
|
||||
localMPI AS BYTE
|
||||
leng AS BYTE
|
||||
func AS BYTE
|
||||
packetNumber AS BYTE
|
||||
END TYPE
|
||||
|
||||
TYPE typDaveInterface BYTE
|
||||
ttimeout AS LONG
|
||||
fd AS typDaveOSserial
|
||||
localMPI AS LONG
|
||||
users AS LONG
|
||||
pname AS BYTE POINTER
|
||||
protocol AS LONG
|
||||
speed AS LONG
|
||||
ackPos AS LONG
|
||||
nextConnection AS DWORD
|
||||
initAdapter AS DWORD
|
||||
connectPLC AS DWORD
|
||||
disconnectPLC AS DWORD
|
||||
disconnectAdapter AS DWORD
|
||||
exchange AS DWORD
|
||||
sendMessage AS DWORD
|
||||
getResponse AS DWORD
|
||||
listReachablePartners AS DWORD
|
||||
END TYPE
|
||||
|
||||
' This holds data for a PLC connection
|
||||
' pointer to used interface
|
||||
' The PLC's address
|
||||
' current message number
|
||||
' message number we need ackknowledge for
|
||||
' length of last message
|
||||
' template of MPI Header, setup once, copied in and then modified
|
||||
' used to retrieve single values from the result byte array
|
||||
' packetNumber in transport layer
|
||||
' position of PDU in outgoing messages. This is different for different transport methodes.
|
||||
' position of PDU in incoming messages. This is different for different transport methodes.
|
||||
' rack number for ISO over TCP
|
||||
' slot number for ISO over TCP
|
||||
TYPE typDaveConnection BYTE
|
||||
AnswLen AS LONG
|
||||
resultPointer AS BYTE POINTER
|
||||
maxPDUlength AS LONG
|
||||
MPIAdr AS LONG
|
||||
pIface AS LONG
|
||||
needAckNumber AS LONG
|
||||
PDUnumber AS LONG
|
||||
ibhSrcConn AS LONG
|
||||
ibhDstConn AS LONG
|
||||
msgIn (0 TO (%daveMaxRawLen)-1) AS BYTE
|
||||
msgOut (0 TO (%daveMaxRawLen)-1) AS BYTE
|
||||
r_resultPointer AS BYTE POINTER
|
||||
PDUstartO AS LONG
|
||||
PDUstartI AS LONG
|
||||
rack AS LONG
|
||||
slot AS LONG
|
||||
connectionNumber AS LONG
|
||||
connectionNumber2 AS LONG
|
||||
messageNumber AS BYTE
|
||||
packetNumber AS BYTE
|
||||
END TYPE
|
||||
'--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ENDIF ' #IF NOT %DEF(%DAVE_INC)
|
||||
6982
contributions/keith/nodave.c
Executable file
6982
contributions/keith/nodave.c
Executable file
File diff suppressed because it is too large
Load Diff
51
contributions/keith/setport.h
Executable file
51
contributions/keith/setport.h
Executable file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Part of Libnodave, a free communication libray for Siemens S7 300/400.
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2001.
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Libnodave; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus //****** ADD
|
||||
extern "C" { //****** ADD
|
||||
#endif //****** ADD
|
||||
|
||||
#ifdef BCCWIN
|
||||
|
||||
#ifdef DOEXPORT
|
||||
#define EXPORTSPEC __declspec (dllexport)
|
||||
#else
|
||||
#define EXPORTSPEC __declspec (dllimport)
|
||||
#endif
|
||||
|
||||
EXPORTSPEC HANDLE __stdcall setPort(char * name, char* baud,char parity);
|
||||
|
||||
EXPORTSPEC int __stdcall closePort(HANDLE port);
|
||||
#endif
|
||||
|
||||
//#ifdef __cplusplus //****** REMOVE moved to top
|
||||
//extern "C" { //****** REMOVE moved to top
|
||||
//#endif //****** REMOVE moved to top
|
||||
|
||||
|
||||
#ifdef LINUX
|
||||
int setPort(char * name, char* baud,char parity);
|
||||
|
||||
int closePort(int port);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
146
contributions/keith/setportw.c
Executable file
146
contributions/keith/setportw.c
Executable file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Part of Libnodave, a free communication libray for Siemens S7 300/400.
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2004.
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define debug 0
|
||||
#define ThisModule "setPort : "
|
||||
#ifdef BCCWIN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "nodave.h"
|
||||
|
||||
extern int daveDebug;
|
||||
|
||||
|
||||
/*
|
||||
You may wonder why a pair of identical file handles is set up and
|
||||
returned. It's for compatibility with an extended UNIX version of
|
||||
this code, which can use two separate pipes for reads and writes.
|
||||
*/
|
||||
|
||||
__declspec(dllexport)
|
||||
HANDLE __stdcall setPort(char * devname, char * baud,char parity /*, HANDLE * wfd*/){
|
||||
HANDLE hComm;
|
||||
DCB dcb;
|
||||
|
||||
hComm = CreateFile( devname,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_WRITE_THROUGH,
|
||||
0);
|
||||
if (daveDebug & daveDebugOpen) {
|
||||
|
||||
printf("setPort %s\n",devname);
|
||||
printf("setPort %s\n",baud);
|
||||
printf("setPort %c\n",parity);
|
||||
}
|
||||
|
||||
// printf("Handle to %s opened! %d\n",devname,hComm);
|
||||
GetCommState(hComm,&dcb);
|
||||
// printf("got Comm State. %d\n ",dcb.BaudRate);
|
||||
dcb.ByteSize = 8;
|
||||
dcb.fOutxCtsFlow=FALSE;
|
||||
dcb.fOutxDsrFlow=FALSE;
|
||||
// dcb.fDtrControl=DTR_CONTROL_DISABLE; // this seems to be the evil. Guess do not understand the meaning of this parameter
|
||||
|
||||
dcb.fDtrControl=DTR_CONTROL_ENABLE;
|
||||
|
||||
dcb.fDsrSensitivity=FALSE;
|
||||
dcb.fInX=FALSE;
|
||||
dcb.fOutX=FALSE;
|
||||
dcb.fNull=FALSE;
|
||||
dcb.fAbortOnError=FALSE;
|
||||
dcb.fBinary=TRUE;
|
||||
dcb.fParity=TRUE;
|
||||
dcb.fOutxCtsFlow=FALSE;
|
||||
dcb.fOutxDsrFlow=FALSE;
|
||||
// dcb.fRtsControl=FALSE; // this seems to be the evil. Guess do not understand the meaning of this parameter
|
||||
// dcb.fRtsControl=TRUE; //****** REMOVE
|
||||
// from winbase.h : //****** ADD
|
||||
//#define RTS_CONTROL_DISABLE 0 //****** ADD
|
||||
//#define RTS_CONTROL_ENABLE 1 //****** ADD
|
||||
//#define RTS_CONTROL_HANDSHAKE 2 //****** ADD
|
||||
dcb.fRtsControl=RTS_CONTROL_ENABLE; //****** ADD
|
||||
//#define RTS_CONTROL_TOGGLE 3 //****** ADD
|
||||
dcb.fTXContinueOnXoff=TRUE;
|
||||
// dcb.StopBits=2; ///that was 2 !!! //****** REMOVE
|
||||
// from winbase.h : //****** ADD
|
||||
//#define ONESTOPBIT 0 //****** ADD
|
||||
//#define ONE5STOPBITS 1 //****** ADD
|
||||
//#define TWOSTOPBITS 2 //****** ADD
|
||||
dcb.StopBits=TWOSTOPBITS; ///that was 2 !!! //****** ADD
|
||||
if (0==strncmp(baud,"115200",6))
|
||||
dcb.BaudRate = CBR_115200;
|
||||
else if (0==strncmp(baud,"57600",5))
|
||||
dcb.BaudRate = CBR_57600;
|
||||
else if (0==strncmp(baud,"38400",5))
|
||||
dcb.BaudRate = CBR_38400;
|
||||
else if (0==strncmp(baud,"19200",5))
|
||||
dcb.BaudRate = CBR_19200;
|
||||
else if (0==strncmp(baud,"9600",4))
|
||||
dcb.BaudRate = CBR_9600;
|
||||
else if (0==strncmp(baud,"4800",4))
|
||||
dcb.BaudRate = CBR_4800;
|
||||
else if (0==strncmp(baud,"2400",4))
|
||||
dcb.BaudRate = CBR_2400;
|
||||
else if (0==strncmp(baud,"1200",4))
|
||||
dcb.BaudRate = CBR_1200;
|
||||
else if (0==strncmp(baud,"600",3))
|
||||
dcb.BaudRate = CBR_600;
|
||||
else if (0==strncmp(baud,"300",3))
|
||||
dcb.BaudRate = CBR_300;
|
||||
else if (daveDebug & daveDebugPrintErrors) {
|
||||
printf(ThisModule "illegal Baudrate: %s\n", baud);
|
||||
}
|
||||
parity=tolower(parity);
|
||||
if (parity == 'e')
|
||||
dcb.Parity = 2;
|
||||
else if (parity == 'o')
|
||||
dcb.Parity = 1;
|
||||
else if (parity == 'n')
|
||||
dcb.Parity = 0;
|
||||
else if (daveDebug & daveDebugPrintErrors) {
|
||||
printf(ThisModule "illegal parity mode:%c\n", parity);
|
||||
}
|
||||
|
||||
|
||||
SetCommState(hComm,&dcb);
|
||||
// printf("got Comm State. %d\n ",dcb.BaudRate);
|
||||
|
||||
//printf("Comm State set.\n");
|
||||
// *wfd=hComm;
|
||||
return hComm;
|
||||
}
|
||||
|
||||
__declspec(dllexport)
|
||||
int __stdcall closePort(HANDLE port){
|
||||
int res=CloseHandle(port);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Changes:
|
||||
|
||||
12/17/2004 1st Version for Windows.
|
||||
04/03/2005 Hopefully really fixed COM port setting.
|
||||
05/08/2005 Removed printfs for quiet operation.
|
||||
16
doc/ARMprocessors.html
Normal file
16
doc/ARMprocessors.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<H1>Compiling Libnodave for ARM processors</H1>
|
||||
Libnodave did not work on ARM processors. It seemed that the processor cannot access a word on a
|
||||
non word boundary (odd address). The following code did not work:
|
||||
<pre>
|
||||
((PDUHeader*)p->header)->plen=daveSwapIed_16(len);
|
||||
</pre>
|
||||
Here the pointer p->header has been set two an odd address. The offset of plen in the
|
||||
structure PDUHeader is even, hence the resulting pointer points at an odd address.
|
||||
The ARM seems to take the previous lower word boundary instead of the calculated address.
|
||||
It seems that no compiler option could prevent this, possibly because the final address is the result of a calculation
|
||||
and not known at comile time. The following work around fixes this.
|
||||
<pre>
|
||||
templen=daveSwapIed_16(len);
|
||||
memcpy(&(((PDUHeader*)p->header)->plen),&templen,sizeof(us));
|
||||
</pre>
|
||||
Memcpy seems to use two subsequent byte accesses and works as expected.
|
||||
30
doc/FAQ.html
Normal file
30
doc/FAQ.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta content="">
|
||||
<style></style>
|
||||
</head>
|
||||
<body>
|
||||
<H1><b>LIBNODAVE</b> FAQ</H1>
|
||||
<H4>Q: Can you give me a documentation about MPI protocol?</H4>
|
||||
A: <a href="MPI.html">Here's what I know</a>
|
||||
<H4>Q: That warning on <b>LIBNODAVE</b> home page, does it mean the software is so dangerous/unreliable?</H4>
|
||||
A: No, it's just there to prevent anybody from holding me responsible for whatever he might do with it. I trust my software. But I heard, in USA a manufacturer of ladders had to put a label on them saying: "Use on firm ground only" and another one: "Do not use on frozen dung."
|
||||
<H4>Q: Why doesn't <b>LIBNODAVE</b> work with my MPI adapter?</H4>
|
||||
A: Haven't heard this for quite while. If you have difficulties, first send me the output from testMPI, once started with and once without the option -2. Also include the exact order code of the adapter. I probably can help if I can provide such an adapter. If not, you may think about giving me access to your computer or sending me the adapter.
|
||||
<H4>Q: Can <b>LIBNODAVE</b> work with CP 5x1x?</H4>
|
||||
A: No, it can't. The reason is that there is no documentation for this hardware that would allow to write drivers for it. There are commercial products that use the drivers that are installed with Step7 or other Siemens software. But they are for Windows only.<br>
|
||||
I guess a speedy USB to MPI adapter could make this hardware obsolete.
|
||||
<H4>Q: How can I support the development of <b>LIBNODAVE</b>?</H4>
|
||||
A: Give feedback. I should like to be able to put as many order codes of supported hard ware on the list as possible.<br>
|
||||
Donations in hardware or money are allways very welcome.
|
||||
<H4>Q: I want to use <b>LIBNODAVE</b> for my project, but will it support future hardware?</H4>
|
||||
A: It does what it does and it is absolutely unlikely that it could fail with future members of S7 family or compatibles. Naturally, I cannot speak about an immaginary S9...
|
||||
<H4>Q: What is the largest block of bytes <b>LIBNODAVE</b> can read/write to a PLC?</H4>
|
||||
A: This is limited by the maximum length of a <a href="pdu.html">PDU</a>, which in turn depends on your CPU type.For 240 byte PDU length, you can read 222 bytes and write 218 bytes in a single transaction.
|
||||
<H4>Q: The xy software can write larger blocks, or?</H4>
|
||||
A: No,whichever software hides that limit from you has to split larger blocks into multiple requests.
|
||||
<H4>Q: Why don't you do that automatically also in <b>LIBNODAVE</b>?</H4>
|
||||
A: <b>LIBNODAVE</b> is for programmers. They will be easily available to do it themselves. On the other hand, automatic splitting would hide a limit that costs performance...
|
||||
</body>
|
||||
</html>
|
||||
44
doc/MPI.html
Normal file
44
doc/MPI.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<H1>MPI details</H1>
|
||||
As many users asked for the details of MPI Interface, protocol and whether there is a way to make your own MPI adapter, here is a brief description of what I know:
|
||||
<H2>Physical Layer</H2>
|
||||
MPI uses RS485 serial communication with parity even and baud rates from 19.2 kBaud to 187.5 or to 12MBaud in newer systems.<br>
|
||||
Want to "sniff" MPI? Set your PLC's MPI speed to 19.2, because this is the only baudrate also supported by PC UARTs. Prepare a ribbon cable with one male and to female Sub-D connectors. Plug it into the PLCs MPI connector, an MPI adapter or CP5x1x into one female and an RS485/RS232 converter or PPI cable into the other one. Now your PC can listen!
|
||||
<H2>Media Arbitration</H2>
|
||||
MPI is basically a variety of Profibus, using the FDL profile.<br>
|
||||
Profibus is a token ring. One master at a time is in posession of the "token", which entitles it to send requests to other devices. It may hold the token for a limited time. Either when that time expires or when it has sent all its requests and has got the answers, it passes the token on to the next known master. From time to time, it asks for the presence of masters with numbers between its own number and the number of the next known master. Thus, new masters are "invited" to participate in the ring.<br>
|
||||
In case of MPI, the PLC in absence of a partner sends the token to itself:
|
||||
<H2>Example</H2>
|
||||
<pre>DC 02 02</pre>
|
||||
After each token passing it sends a request to get the diagnostic state of device number x:
|
||||
<pre>10 x 02 49 bcc 16</pre>
|
||||
This is repeated for all free device numbers. If you connect an MPI adapter it will do nothing, not even respond. After you set it up, e.g. with daveInitAdapter(), it has its MPI address, e.g. 0. Now it will respond as soon as the PLC requests diagnostic state from device 0. The PLC then passes the token to it:
|
||||
<pre>DC 00 02</pre>
|
||||
Now the adapter, if it has a message to send, sends this message in a telegram of variable length
|
||||
to the CPU:
|
||||
<pre>68,11,11,68 //message, 17 bytes long </pre>
|
||||
<pre> 82,80,6D,00,14, // request telegram to 2 from 0, SRD high DSAP=0,SSAP=0x14</pre>
|
||||
<pre> E0,04,00,80,00,02,00,02,01,00,01,00,ED,16, //the "payload" message </pre>
|
||||
<pre> E5, // short ackknowledge from CPU</pre>
|
||||
<pre>DC,02,00, //adapter passes token to CPU</pre>
|
||||
<pre>10,05,02,49,50,16, //CPU requests diagnostic state from device 5</pre>
|
||||
<pre>DC,00,02, //CPU passes token to adapter</pre>
|
||||
<pre>DC,02,00, //adapter passes token back to CPU</pre>
|
||||
<pre>10,06,02,49,51,16, //CPU requests diagnostic state from device 6</pre>
|
||||
<pre> //I'm not sure, but I guess CPU waits for some amount of time for a response.
|
||||
//This time should be part of Profibus specifications.</pre>
|
||||
<pre>68,11,11,68, //CPU sends message with length 17</pre>
|
||||
<pre> 80,82,6C,14,14, // response telegram to 0 from 2, DSAP=14,SSAP=0x14</pre>
|
||||
<pre> D0,04,00,80,00,02,00,02,01,00,01,00,F0,16,//the "payload" message </pre>
|
||||
<pre> E5, // short ackknowledge from adapter</pre>
|
||||
<pre>DC,00,02, //CPU passes token to adapter</pre>
|
||||
<H2>Payload</H2>
|
||||
The payload messages are something I want to call <a href=S7communication.html>"S7 communication"</a>. They are common for all sorts of transport (MPI,PPI, ISO over TCP). Payload messages are sent to an MPI adapter either through 3964R (which is used by LIBNODAVE and all 3rd party software I know) or through another protocol used by Step7. The protocol used by Step7 has a more complicated checksum(CRC?). It also sends a kind of "keep alive message" when the connection is idle. This keep alive message changes after packets with payload, so the partner will know if a packet with payload got lost.<br>
|
||||
The <a href=S7communication.html>S7 communication</a> over MPI introduces additional ackknowledges for each "payload" message generated by PLC or PC and passed over Profibus FDL by the adapter. These are neither present in PPI nor ISO/TCP.
|
||||
<H2>Homemade MPI Adapters</H2>
|
||||
<li>Find a uC with 2 UARTs of which one can handle 12MBaud.</li>
|
||||
<li>Implement Profibus token passing.</li>
|
||||
<li>Implement Profibus variable length messages.</li>
|
||||
<li>Implement 3964R for PC side.</li>
|
||||
<li>Implement the adapter init/disconnect commends.</li>
|
||||
<li>Implement the "Step7 protocol" for PC side, if you want to use it with Step7.</li>
|
||||
<li>Be aware that it is not tested for Profibus compliance. So you are at risk to stop dangerous machinery...</li>
|
||||
26
doc/PDUerrorcodes.html
Normal file
26
doc/PDUerrorcodes.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<H1>Error codes</H1>
|
||||
<H2>Error codes reported in 12 byte headers of type 2 and 3 PDUs</H2>
|
||||
<table>
|
||||
<tr><td>0</td><td>ok</td></tr>
|
||||
<tr><td>0x8000</td><td>function already occupied.</td></tr>
|
||||
<tr><td>0x8001</td><td>not allowed in current operating status.</td></tr>
|
||||
<tr><td>0x8101</td><td>hardware fault</td></tr>
|
||||
<tr><td>0x8103</td><td>object access not allowed.</td></tr>
|
||||
<tr><td>0x8104</td><td>context is not supported.</td></tr>
|
||||
<tr><td>0x8105</td><td>invalid address.</td></tr>
|
||||
<tr><td>0x8106</td><td>data type not supported.</td></tr>
|
||||
<tr><td>0x8107</td><td>data type not consistent.</td></tr>
|
||||
<tr><td>0x810A</td><td>object does not exist.</td></tr>
|
||||
<tr><td>0x8500</td><td>incorrect PDU size.</td></tr>
|
||||
<tr><td>0x8702</td><td>address invalid."</td></tr>
|
||||
<tr><td>0xd201</td><td>block name syntax error.</td></tr>
|
||||
<tr><td>0xd202</td><td>syntax error function parameter.</td></tr>
|
||||
<tr><td>0xd203</td><td>syntax error block type.</td></tr>
|
||||
<tr><td>0xd204</td><td>no linked block in storage medium.</td></tr>
|
||||
<tr><td>0xd205</td><td>object already exists.</td></tr>
|
||||
<tr><td>0xd206</td><td>object already exists.</td></tr>
|
||||
<tr><td>0xd207</td><td>block exists in EPROM.</td></tr>
|
||||
<tr><td>0xd209</td><td>block does not exist.</td></tr>
|
||||
<tr><td>0xd20e</td><td>no block does not exist.</td></tr>
|
||||
<tr><td>0xd210</td><td>block number too big.</td></tr>
|
||||
</table>
|
||||
4
doc/S7Communication.html
Normal file
4
doc/S7Communication.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<H1>S7 Communication details</H1>
|
||||
The basic unit in S7 communication ia a PDU (protocol data unit). It is made up of:
|
||||
<li>A 10 or 12 byte header</li>
|
||||
<li>A parameter field of variable length</li>
|
||||
12
doc/SZL.html
Normal file
12
doc/SZL.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<H1>Reading SZL lists</H1>
|
||||
The CPUs of the 300 and 400 family provide lists of their internal states and properties. German Siemens terminology calls them SZL (<b>S</b>ystem-<b>Z</b>ustands<b>L</b>isten). These lists are what your programming Software reads when showing the diagnostic buffer, the state of run/stop, the amount of memory and much more. LIBNODAVE provides the function:
|
||||
<pre>
|
||||
daveReadSZL(daveConnection * dc, int ID, int index, void * buf);
|
||||
</pre>
|
||||
to read these lists.<br>
|
||||
ID 0, index 0 retrieves a list of available SZL-IDs on your PLC. I don't know how to find out
|
||||
the available or meaningful indices. In most cases, index 0 is the whole list, while other
|
||||
indices retrieve parts of it.<br>
|
||||
Use testMPI -z for some examples and testMPI -a for the complete contents of your PLCs SZL-lists
|
||||
(with index 0, so there may exist lists that do not have an index 0).<br>
|
||||
Refer do Siemens documentation for the meaning of IDs and indices.
|
||||
18
doc/area.html
Normal file
18
doc/area.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<H1>PLC memory areas</H1>
|
||||
<table>
|
||||
<tr><th>Name</th><th>constant</th><th>Example item(German)</th><th>Example item(English)</th><th>Example read call</th></tr>
|
||||
<tr><td>Data blocks</td><td>daveDB</td><td>DB3.DBD4</td><td>DB3.DBD4</td><td>daveReadBytes(dc,daveDB,3,4,4,NULL)</td></tr>
|
||||
<tr><td>Flags/Markers</td><td>daveFlags</td><td>MW4</td><td>FW4</td><td>daveReadBytes(dc,daveFlags,0,4,2,NULL)</td></tr>
|
||||
<tr><td>Input memory image</td><td>daveInputs</td><td>EB2</td><td>IB2</td><td>daveReadBytes(dc,daveInputs,0,2,1,NULL)</td></tr>
|
||||
<tr><td>Output memory image</td><td>daveOutputs</td><td>AD8</td><td>QD8</td><td>daveReadBytes(dc,daveOutputs,0,8,4,NULL)</td></tr>
|
||||
<tr><td>Timers</td><td>daveTimer</td><td>T2</td><td>T2</td><td>daveReadBytes(dc,daveTimer,0,2,2,NULL)</td></tr>
|
||||
<tr><td>Counters</td><td>daveCounter</td><td>Z2</td><td>C2</td><td>daveReadBytes(dc,daveCounter,0,2,2,NULL)</td></tr>
|
||||
<tr><td>Direct I/O</td><td>daveP</td><td>PEW4</td><td>PIW4</td><td>daveReadBytes(dc,daveP,0,4,2,NULL)</td></tr>
|
||||
<tr><td>System information of 200 family</td><td>daveSysInfo</td><td></td><td></td><td>daveReadBytes(dc,daveSysInfo,0,0,20,NULL)</td></tr>
|
||||
<tr><td>Data (V-memory) in S7-200</td><td>daveDB</td><td>VW1234</td><td>VW1234</td><td>daveReadBytes(dc,daveDB,1,1234,2,NULL)</td></tr>
|
||||
<tr><td>System flag area of 200 family</td><td>daveSysFlags</td><td>SMB0</td><td>SFB0?</td></tr>
|
||||
<tr><td>Analog input words of 200 family</td><td>daveAnaIn</td><td>AEW0</td><td>AIW0?</td></tr>
|
||||
<tr><td>Analog output words of 200 family</td><td>daveAnaOut</td><td>AAW0</td><td>AQW0?</td></tr>
|
||||
<tr><td>IEC Timers</td><td>daveTimer200</td><td>T2</td><td>T2</td><td>daveReadBytes(dc,daveTimer200,0,2,2,NULL)</td></tr>
|
||||
<tr><td>IEC Counters</td><td>daveCounter200</td><td>Z2</td><td>C2</td><td>daveReadBytes(dc,daveCounter200,0,2,2,NULL)</td></tr>
|
||||
</table>
|
||||
73
doc/conversions.html
Normal file
73
doc/conversions.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<H1>Conversion routines</H1>
|
||||
The buffers used by daveReadBytes() and daveWriteBytes() will contain a copy of the PLC memory area. This means: If you read from the beginning of DB2, the buffer will contain a byte for byte copy of DB2. The values are the same and in the same order, as what you get when you observe byte variables in Step7. Example:<br>
|
||||
<table>
|
||||
<tr><td>DB20.DBB0</td><td>26</td></tr>
|
||||
<tr><td>DB20.DBB1</td><td>37</td></tr>
|
||||
<tr><td>DB20.DBB2</td><td>48</td></tr>
|
||||
<tr><td>DB20.DBB3</td><td>15</td></tr>
|
||||
<tr><td>DB20.DBB4</td><td>16</td></tr>
|
||||
<table>
|
||||
You are free to interpret these values as single bytes or multibyte values,the same way as you can do this in Step7 AWL.:<br>
|
||||
Also it is unusual, you can load a real value from DB20.DBD1:<br>
|
||||
<pre>
|
||||
L DB20.DBD1
|
||||
L 2.0
|
||||
*R
|
||||
</pre>
|
||||
A further complication results from the fact that Siemens PLCs store multibyte values beginning with the most significant byte (big endian) while Intel based PCs store the least significant byte first (little endian).<br>
|
||||
It is not possible to convert the byte order in the daveReadBytes() or daveWriteBytes() fuctions
|
||||
because the start position of each multibyte value is not known then.<br>
|
||||
You are free to place such values at arbitrary byte addresses in your PLC program.
|
||||
The same adresses must in turn be used to retrieve values from the copy of PLC memory.
|
||||
If you have a data block DB2 with the following layout:<br>
|
||||
<table>
|
||||
<tr><td>DBB 0</td><td>BYTE</td></tr>
|
||||
<tr><td>DBD 1</td><td>DWORD</td></tr>
|
||||
<tr><td>DBD 5</td><td>REAL</td></tr>
|
||||
</table>
|
||||
You can retrieve the single values in three ways:<br>
|
||||
1. From the intenal buffer. After a successful call, an internal pointer points to the 1st byte.
|
||||
Now use daveGetU8(dc) to get the value of the first byte as an unsigned value. The internal buffer pointer
|
||||
is incremented by 1, now pointing to the copy of DBD1. Use daveGetS32(dc) to get the value of the
|
||||
of the next 4 bytes as a signed value. The internal pointer is incremented by 4, now pointing to
|
||||
the copy of DBD5. Use daveGetFloat(dc) to get the value of the next 4 bytes as a single precision
|
||||
float.<br>
|
||||
2. From the internal buffer, specifying a position. Use daveGetU8at(dc,0) to get the value of the
|
||||
first byte as an unsigned value. Next use daveGetS32at(dc,1) to get the value of the 4 bytes
|
||||
starting at 1 as a signed value. Finally, use daveGetFloatat(dc,5) to get the value of the 4 bytes
|
||||
starting at 5 as a single precision float. You may perform these operation in any order and also
|
||||
repeat them.<br>
|
||||
3. From a user buffer. Use daveGetU8from(buffer) to get the value of the first byte as an
|
||||
unsigned value. Use daveGetS32from(buffer+1) to get the value of the 4 bytes at buffer+1, i.e.
|
||||
DBD 1, as a signed value. Use daveGetFloatat(buffer+5) to get the value of the 4 bytes starting
|
||||
at buffer+5 as a single precision float, i.e. DBD5.<br>
|
||||
The conversion functions are named after the bit length and signedness they assume:
|
||||
<table>
|
||||
<tr><th>int buffer</th><th>int buffer+pos</th><th>buffer pointer</th><th>size</th><th>signed</th><th>C-return type</th><th>Pascal ret type</th></tr>
|
||||
<tr><td>daveGetU8</td><td>daveGetU8at</td><td>daveGetU8from</td><td>8 bit=1 byte</td><td>no</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetS8</td><td>daveGetS8at</td><td>daveGetS8from</td><td>8 bit=1 byte</td><td>yes</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetU16</td><td>daveGetU16at</td><td>daveGetU16from</td><td>16 bit=2 byte</td><td>no</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetS16</td><td>daveGetS16at</td><td>daveGetS16from</td><td>16 bit=2 byte</td><td>yes</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetU32</td><td>daveGetU32at</td><td>daveGetU32from</td><td>32 bit=4 byte</td><td>no</td><td>unsigned int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetS32</td><td>daveGetS32at</td><td>daveGetS32from</td><td>32 bit=4 byte</td><td>yes</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetFloat</td><td>daveGetFloatat</td><td>daveGetFloatfrom</td><td>32 bit=4 byte</td><td>yes</td><td>float</td><td>single</td></tr>
|
||||
</table>
|
||||
|
||||
There had been an older set of those functions named after data types, e.g.
|
||||
daveGetDWORD(). Those functions should not be used any more, as there names might be
|
||||
misunderstandable between PLC and C or other programming languages. They are still supported
|
||||
for compatibility with older versions. These functions had been inlined in earlier versions
|
||||
but are now not inlined by default, because other languages than C cannot make use of inline
|
||||
definitions in a C header file.
|
||||
<h4>Notes:</h4>
|
||||
Most commercial libraries handle the conversion issue differently: They provide functions to read one or a set of words, one or a set of long words, one or a set of reals. On the first glance, this might seem more convenient and it <b>is</b> as long as it can be applied to PLC memory areas containing only elements of the same type and size. But when you have to deal with data of mixed type and size, you would have to use another call to daveReadBytes() each time the type or size differs from the former. And each call contributes the overhead of the protocol and the response time of the PLC. Other libraries provide a way to read multiple items with a single call. So does <b>Libnodave</b>. You could also use it to retrieve data located on different boundaries. But this is limited to 20 items by the PLC. And it introduces some overhead as an address has to be transmitted for each item in the request. Use read multiple items to access data from different DBs or other memory areas when the combined results will fit in a single response.
|
||||
<table>
|
||||
<tr><th>When you want to read</td><th>do</th><th>remark</th></tr>
|
||||
<tr><td>DB20.DBD0..DBD20</td><td>read 24 bytes starting at DBB0</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD8 and DBD20</td><td>read 24 bytes starting at DBB0</td><td>just do not evaluate bytes 11 to 19 of result.</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD8 and DBD120</td><td>either read 124 bytes starting at DBB0</td><td>just do not evaluate bytes 11 to 119 of result.</td></tr>
|
||||
<tr><td></td><td>or use multiple read on: item1:DB20.DBD0..DBD8, item2:DB20.DBD120 </td><td>you have to deal with the result set.</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD8 and DB21.DBD120</td><td>use multiple read on: item1:DB20.DBD0..DBD8, item2:DB21.DBD120 </td><td>this is the only way to read from different DBs with a single request/reponse.</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD118 and DB21.DBD4..DBD80</td><td>use two calls to daveReadBytes</td><td>this is the only way if the two combined results will not fit into a single PDU.</td></tr>
|
||||
<table>
|
||||
|
||||
18
doc/daveConnection.html
Normal file
18
doc/daveConnection.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<H1>daveConnection</H1>
|
||||
A structure representing the physical connection to a single PLC.
|
||||
daveConnection stores all properties that are unique to a single PLC:
|
||||
<li>The MPI address of this PLC.</li>
|
||||
<li>The rack the PLC is in.</li>
|
||||
<li>The slot the PLC is in.</li>
|
||||
The structure daveConnection is created and initialized by daveNewConnection:
|
||||
<pre>
|
||||
daveConnection * dc;
|
||||
dc =daveNewConnection(di, MPI, rack, slot);
|
||||
</pre>
|
||||
The parameters are:
|
||||
<li>di: a <a href=daveInterface.html>daveInterface</li>
|
||||
<li>MPI: the address of the PLC (only meaningful for MPI and PPI).</li>
|
||||
<li>rack: The rack the CPU is mounted in (normally 0, only meaningful for ISO over TCP).</li>
|
||||
<li>slot: The slot number the CPU is mounted in (normally 2, only meaningful for ISO over TCP)</li>
|
||||
<H3>Notes:</H3>
|
||||
In case of PPI communication, the PPI address of the partner PLC must be put into the MPI address parameter. The local PPI address must be put into the local MPI address parameter when calling <a href=daveInterface.html> daveNewInterface()</a>.
|
||||
41
doc/daveInterface.html
Normal file
41
doc/daveInterface.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<H1>daveInterface</H1>
|
||||
A structure representing the physical connection to a PLC or a network of PLCs (e.g. like MPI).
|
||||
daveInterface stores all those properties that are common to a network of PLCs:
|
||||
<li>- The local address used by your computer.</li>
|
||||
<li>- The speed used in this network.</li>
|
||||
<li>- The protocol type used in this network.</li>
|
||||
<li>- A name which is used when printing out debug messages.</li>
|
||||
The structure daveInterface is created and initialized by daveNewInterface:
|
||||
<pre>
|
||||
daveInterface * di;
|
||||
di =daveNewInterface(fds, "IF1", localMPI, daveProtoXXX, daveSpeedYYY);
|
||||
</pre>
|
||||
The parameters are:
|
||||
<li>fds: a <a href=daveOSserialType.html>_daveOSserialType</li>
|
||||
<li>a Name</li>
|
||||
<li>localMPI: the address used by your computer/adapter (only meaningful for MPI and PPI)</li>
|
||||
<li>daveProtoXXX: a constant specifying the protocol to be used on this interface</li>
|
||||
<li>daveSpeedYYY: a constant specifying the speed to be used on this interface. (only meaningful for MPI and Profibus)</li>
|
||||
<H4>Protocol types to be used with newInterface:</H4>
|
||||
<table>
|
||||
<tr><th>Name</th><th>Meaning</th></tr>
|
||||
<tr><td>daveProtoMPI</td><td>MPI for S7 300/400</td></tr>
|
||||
<tr><td>daveProtoMPI2</td><td>MPI for S7 300/400, "Andrew's version"</td></tr>
|
||||
<tr><td>daveProtoPPI</td><td>PPI for S7 200</td></tr>
|
||||
<tr><td>daveProtoISOTCP</td><td>ISO over TCP</td></tr>
|
||||
<tr><td>daveProtoISOTCP243</td><td>ISO over TCP with CP243</td></tr>
|
||||
<tr><td>daveProtoIBH</td><td>MPI with IBH NetLink MPI to ethernet gateway</td></tr>
|
||||
</table>
|
||||
<H4>MPI/ProfiBus speed constants:</H4>
|
||||
<table>
|
||||
<tr><td> daveSpeed9k</td></tr>
|
||||
<tr><td> daveSpeed19k</td></tr>
|
||||
<tr><td> daveSpeed187k</td></tr>
|
||||
<tr><td> daveSpeed500k </td></tr>
|
||||
<tr><td> daveSpeed1500k</td></tr>
|
||||
<tr><td> daveSpeed45k </td></tr>
|
||||
<tr><td> daveSpeed93k </td></tr>
|
||||
</table>
|
||||
The name field is provided for applications which may communicate with multiple PLCs on multiple
|
||||
pgysical connections. In such cases, the name helps to tell which interface an error message
|
||||
comes from.
|
||||
32
doc/daveOSserialType.html
Normal file
32
doc/daveOSserialType.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<H1>_daveOSserialType </H1>
|
||||
A wrapper type that contains variables representing the incoming (rfd) and outgoing (wfd) communication
|
||||
channels on OS level. For LINUX and UNIX like systems, these are file descriptors, for Windows, they are handles.
|
||||
For bidirectional channels, rfd and wfd are identical. The reasons for having separate in and out channels are:<br>
|
||||
1. On Unix-like systems, you can use two half duplex (unidirectional)
|
||||
pipes. While there is no possibility to establish a pipe directly to the PLC, a helper program
|
||||
or a PLC simulator might provide such pipes.<br>
|
||||
2. On not yet supported systems, e.g. microcontrollers or DOS with a special support for interrupt
|
||||
controlled serial communication, these variables probably will contain addresses of different low
|
||||
level routines or data structures which provide an interface to low level character I/O.<br>
|
||||
In case of Unix or Windows, the variables are just identical.<br>
|
||||
<H4>LINUX definition:</H4>
|
||||
<pre>
|
||||
typedef struct {
|
||||
int rfd;
|
||||
int wfd;
|
||||
} _daveOSserialType;
|
||||
</pre>
|
||||
<H4>WIN32 definition:</H4>
|
||||
<pre>
|
||||
typedef struct {
|
||||
HANDLE rfd;
|
||||
HANDLE wfd;
|
||||
} _daveOSserialType;
|
||||
</pre>
|
||||
<H4>Possible definition on a microcontroller:</H4>
|
||||
<pre>
|
||||
typedef struct {
|
||||
char * rfd; // pointer to a receivebuffer
|
||||
*(void(char)) wfd; // pointer to a send routine similar to putchar()
|
||||
} _daveOSserialType;
|
||||
</pre>
|
||||
45
doc/daveReadBytes.html
Normal file
45
doc/daveReadBytes.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<H1>daveReadBytes</H1>
|
||||
Reads a sequence of bytes from PLC memory.
|
||||
<pre>
|
||||
int daveReadBytes(daveConnection * dc, int area, int DB, int start, int len, void * buffer);
|
||||
</pre>
|
||||
<H3>Parameters:</H3>
|
||||
<li>dc: A pointer to a daveConnection structure representing an established connection.</li>
|
||||
<li><a href=area.html>area</a>: A constant that specifies a memory area in the PLC.</li>
|
||||
<li>DB: The number of a data block. Only meaningful if area is daveDB. Use 0 oterwise.</li>
|
||||
<li>start: The address of the first byte in the block.</li>
|
||||
<li>len: The number of bytes to read.</li>
|
||||
<li>buffer: A pointer to some memory space where you want the result to be copied too.</li>
|
||||
<H3>Result:</H3>
|
||||
The function returns 0 on success. Nonzero return codes may be passed to daveStrerror() to
|
||||
get a textual explanation of what happened. Generally, positive error codes represent errors
|
||||
reported by the PLC, while negative ones represent errors detected by LIBNODAVE, e.g. no
|
||||
response from the PLC.
|
||||
<H3>Hints:</H3>
|
||||
<H4>len:</H4>
|
||||
Note that timer, counters and the analog input/output words of the 200 family are
|
||||
allways words (2 bytes). To read n of them, you have to specify 2xn bytes as len.
|
||||
<H4>buffer:</H4>
|
||||
You may call daveReadBytes() without a buffer specifying NULL (C) or nil (Pascal). There is,
|
||||
however, an internal buffer that is part of the <a href=daveConnection.html>daveConnection</a>
|
||||
structure. This internal buffer allways holds the result from the last read operation.
|
||||
<H4>Maximum length:</H4>
|
||||
The maximum size of a block in S7-Communication is limited by the size of a message structure
|
||||
called<a href=pdu.html>PDU</a>. Each call to daveReadBytes causes a the exchange of a request
|
||||
and a response PDU. The result data must fit into the "payload" area of a response PDU. This
|
||||
means a maximum block length is PDU size -18 bytes for read. A typical PDU size is 240 Byte,
|
||||
limiting read calls to 222 byte result length. If you need more data, you need to use multiple
|
||||
calls to daveReadBytes().
|
||||
<H4>Efficiency:</H4>
|
||||
Each call to daveReadBytes() causes a the exchange of a request
|
||||
and a response PDU together with prefixes, ackknowledges and what else the transport layer
|
||||
requires. Therefore you should try to read as much as possible in a single call. Example:<br>
|
||||
<pre>
|
||||
daveReadBytes(dc, daveDB, 5, 68, 14, appBuffer);
|
||||
</pre>
|
||||
reads DBD68 and DBD78 and everything in between and fills the range appBuffer+4 to appBuffer+9
|
||||
with 6 unwanted bytes, but it is much faster than:
|
||||
<pre>
|
||||
daveReadBytes(dc, daveDB, 5, 68, 4, appBuffer);
|
||||
daveReadBytes(dc, daveDB, 5, 78, 4, appBuffer+4);
|
||||
</pre>
|
||||
40
doc/daveWriteBytes.html
Normal file
40
doc/daveWriteBytes.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<H1>daveWriteBytes</H1>
|
||||
Write a sequence of bytes from a buffer to PLC memory.
|
||||
<pre>
|
||||
int daveWriteBytes(daveConnection * dc, int area, int DB, int start, int len, void * buffer);
|
||||
</pre>
|
||||
<H4>Parameters:</H4>
|
||||
<li>dc: A pointer to a daveConnection structure representing an established connection.</li>
|
||||
<li><a href=area.html>area</a>: A constant that specifies a memory area in the PLC.</li>
|
||||
<li>DB: The number of a data block. Only meaningful if area is daveDB. Use 0 oterwise.</li>
|
||||
<li>start: The address of the first byte in the block.</li>
|
||||
<li>len: The number of bytes to read.</li>
|
||||
<li>buffer: A pointer to some memory space where you want the result to be copied too.</li>
|
||||
<H3>Hints:</H3>
|
||||
<H4>len:</H4>
|
||||
Note that timer, counters and the analog input/output words of the 200 family are
|
||||
allways words (2 bytes). To read n of them, you have to specify 2xn bytes as len.
|
||||
<H4>buffer:</H4>
|
||||
You may call daveReadBytes() without a buffer specifying NULL (C) or nil (Pascal). There is,
|
||||
however, an internal buffer that is part of the <a href=daveConnection.html>daveConnection</a>
|
||||
structure. This internal buffer allways holds the result from the last read operation.
|
||||
<H4>Maximum length:</H4>
|
||||
The maximum size of a block in S7-Communication is limited by the size of a message structure
|
||||
called<a href=pdu.html>PDU</a>. Each call to daveReadBytes causes a the exchange of a request
|
||||
and a response PDU. The result data must fit into the "payload" area of a response PDU. This
|
||||
means a maximum block length is PDU size -18 bytes for read. A typical PDU size is 240 Byte,
|
||||
limiting read calls to 222 byte result length. If you need more data, you need to use multiple
|
||||
calls to daveReadBytes().
|
||||
<H4>Efficiency:</H4>
|
||||
Each call to daveReadBytes() causes a the exchange of a request
|
||||
and a response PDU together with prefixes, ackknowledges and what else the transport layer
|
||||
requires. Therefore you should try to read as much as possible in a single call. Example:<br>
|
||||
<pre>
|
||||
daveReadBytes(dc, daveDB, 5, 68, 14, appBuffer);
|
||||
</pre>
|
||||
reads DBD68 and DBD78 and everything in between and fills the range appBuffer+4 to appBuffer+9
|
||||
with 6 unwanted bytes, but it is much faster than:
|
||||
<pre>
|
||||
daveReadBytes(dc, daveDB, 5, 68, 4, appBuffer);
|
||||
daveReadBytes(dc, daveDB, 5, 78, 4, appBuffer+4);
|
||||
</pre>
|
||||
641
doc/functions.html
Normal file
641
doc/functions.html
Normal file
@@ -0,0 +1,641 @@
|
||||
<H1>List of functions, structures and constants<H1>
|
||||
<H2>Constants</H2>
|
||||
<Pre>
|
||||
/*
|
||||
This is a wrapper for the serial or ethernet interface. This is here to make porting easier.
|
||||
*/
|
||||
typedef struct {
|
||||
int rfd;
|
||||
int wfd;
|
||||
} _daveOSserialType;
|
||||
typedef struct {
|
||||
HANDLE rfd;
|
||||
HANDLE wfd;
|
||||
} _daveOSserialType;
|
||||
</Pre>
|
||||
<H3>some frequently used ASCII control codes:</H3>
|
||||
<Pre>
|
||||
DLE
|
||||
ETX
|
||||
STX
|
||||
SYN
|
||||
</Pre>
|
||||
<H3>Protocol types to be used with <a href=daveInterface.html>newInterface</a>:</H3>
|
||||
<table>
|
||||
<tr><th>Name</th><th>Meaning</th></tr>
|
||||
<tr><td>daveProtoMPI</td><td>MPI for S7 300/400</td></tr>
|
||||
<tr><td>daveProtoMPI2</td><td>MPI for S7 300/400, "Andrew's version"</td></tr>
|
||||
<tr><td>daveProtoMPI3</td><td>MPI for S7 300/400, The version Step7 uses. Not yet implemented.</td></tr>
|
||||
<tr><td>daveProtoPPI</td><td>PPI for S7 200</td></tr>
|
||||
<tr><td>daveProtoISOTCP</td><td>ISO over TCP</td></tr>
|
||||
<tr><td>daveProtoISOTCP243</td><td>ISO over TCP with CP243</td></tr>
|
||||
<tr><td>daveProtoIBH</td><td>MPI with IBH NetLink MPI to ethernet gateway</td></tr>
|
||||
</table>
|
||||
<H3>ProfiBus/MPI speed constants to be used with <a href=daveInterface.html>newInterface</a>:</H3>
|
||||
<table>
|
||||
<tr><td>daveSpeed9k</td></tr>
|
||||
<tr><td>daveSpeed19k</td></tr>
|
||||
<tr><td>daveSpeed187k</td></tr>
|
||||
<tr><td>daveSpeed500k </td></tr>
|
||||
<tr><td>daveSpeed1500k</td></tr>
|
||||
<tr><td>daveSpeed45k </td></tr>
|
||||
<tr><td>daveSpeed93k </td></tr>
|
||||
</table>
|
||||
<H3>Some S7 Communication function codes (yet unused ones may be incorrect).</H3>
|
||||
These codes are used as the first byte of parameters in a <a href=pdu.html>PDU</a>.
|
||||
<table>
|
||||
<tr><th>Name</th><th>Meaning</th></tr>
|
||||
<tr><td>daveFuncOpenS7Connection</td><td>connect to a PLC, negotiate PDU length</td></tr>
|
||||
<tr><td>daveFuncRead</td><td>marks a read requeast</td></tr>
|
||||
<tr><td>daveFuncWrite</td><td>marks a write requeast</td></tr>
|
||||
<tr><td>daveFuncStartUpload</td><td>initiates the transmission of a code block from PLC to programmer</td></tr>
|
||||
<tr><td>daveFuncUpload</td><td>continues the transmission of a part of a code block from PLC to programmer</td></tr>
|
||||
<tr><td>daveFuncEndUpload</td><td<td>ends the transmission of a part of a code block from PLC to programmer</td></tr>
|
||||
</table>
|
||||
<H3> S7 specific constants:</H3>
|
||||
<H4>Block Type codes</H4>
|
||||
|
||||
S7 specific constants:
|
||||
<Pre>
|
||||
daveBlockType_OB
|
||||
daveBlockType_DB
|
||||
daveBlockType_SDB
|
||||
daveBlockType_FC
|
||||
daveBlockType_SFC
|
||||
daveBlockType_FB
|
||||
daveBlockType_SFB
|
||||
<H4>Memory Area Codes</H4>
|
||||
Use these constants for parameter "area" in daveReadBytes and daveWriteBytes.
|
||||
<table>
|
||||
<tr><th>Name</th><th>Meaning</th></tr>
|
||||
<tr><td>daveSysInfo 0x3</td><td>System info of 200 family</td></tr>
|
||||
<tr><td>daveSysFlags</td><td>System flags of 200 family</td></tr>
|
||||
<tr><td>daveAnaIn</td><td>analog inputs of 200 family</td></tr>
|
||||
<tr><td>daveAnaOut</td><td>analog outputs of 200 family</td></tr>
|
||||
<tr><td>daveInputs</td><td>Input image memory</td></tr>
|
||||
<tr><td>daveOutputs</td><td>Output image memory</td></tr>
|
||||
<tr><td>daveFlags</td><td>Flags (Merker) area</td></tr>
|
||||
<tr><td>daveDB</td><td>Data blocks in 300 and 400, V-Memory in 200</td></tr>
|
||||
<tr><td>daveCounter</td><td>Counters in 300 and 400</td></tr>
|
||||
<tr><td>daveTimer</td><td>Timers in 300 and 400</td></tr>
|
||||
</table>
|
||||
<H3>Function Result Codes.</H3>
|
||||
Genarally, 0 means ok, >0 are results (also errors) reported by the PLC, <0 means error reported by library code.
|
||||
<table>
|
||||
<tr><th>Name</th><th>Value</th><th>Meaning</th></tr>
|
||||
<tr><td>daveResOK</td><td>0</td><td>all ok</td></tr>
|
||||
<tr><td>daveResMultipleBitsNotSupported</td><td>6</td><td>CPU tells it does not support to read a bit block with a length other than 1 bit</td></tr>
|
||||
<tr><td>daveResItemNotAvailable200</td><td>3</td><td>means a a piece of data is not available in the CPU, e.g. when trying to read a non existing DB or bit bloc of length<>1. This code seems to be specific to 200 family.</td></tr>
|
||||
<tr><td>daveResItemNotAvailable</td><td>10</td><td> means a a piece of data is not available in the CPU, e.g. when trying to read a non existing DB</td></tr>
|
||||
<tr><td>daveAddressOutOfRange</td><td>5</td><td>means the data address is beyond the CPUs address range</td></tr>
|
||||
<tr><td>daveResCannotEvaluatePDU</td><td>-123</td><td></td></tr>
|
||||
<tr><td>daveResCPUNoData</td><td>-124</td><td></td></tr>
|
||||
<tr><td>daveUnknownError</td><td>-125</td><td></td></tr>
|
||||
<tr><td>daveEmptyResultError</td><td>-126</td><td></td></tr>
|
||||
<tr><td>daveEmptyResultSetError</td><td>-127</td><td> </td></tr>
|
||||
</table>
|
||||
<H3>Error code to message string conversion:</H3>
|
||||
Call this function to get an explanation for error codes returned by other functions.
|
||||
<pre>
|
||||
char * daveStrerror(int code);
|
||||
</pre>
|
||||
<H3>Max number of bytes in a single message.</H3>
|
||||
An upper limit for MPI over serial is:<br>
|
||||
<pre>
|
||||
8 byte transport header
|
||||
+2*240 max PDU len *2 if every character were a DLE
|
||||
+3 DLE,ETX and BCC
|
||||
= 491
|
||||
Later I saw some programs offering up to 960 bytes in PDU size negotiation
|
||||
|
||||
Max number of bytes in a single message.
|
||||
An upper limit for MPI over serial is:
|
||||
8 transport header
|
||||
+2*960 max PDU len *2 if every character were a DLE
|
||||
+3 DLE,ETX and BCC
|
||||
= 1931
|
||||
|
||||
For now, we take the rounded max of all this to determine our buffer size. This is ok
|
||||
for PC systems, where one k less or more doesn't matter.
|
||||
|
||||
#define daveMaxRawLen 2048
|
||||
</pre>
|
||||
<H3>Some definitions for debugging:</H3>
|
||||
<table>
|
||||
<tr><td>daveDebugRawRead</td><td>Show the single bytes received</td></tr>
|
||||
<tr><td>daveDebugSpecialChars</td><td>Show when special chars are read</td></tr>
|
||||
<tr><td>daveDebugRawWrite</td><td>Show the single bytes written</td></tr>
|
||||
<tr><td>daveDebugListReachables</td><td>Show the steps when determine devices in MPI net</td></tr>
|
||||
<tr><td>daveDebugInitAdapter</td><td>Show the steps when Initilizing the MPI adapter</td></tr>
|
||||
<tr><td>daveDebugConnect</td><td>Show the steps when connecting a PLC</td></tr>
|
||||
<tr><td>daveDebugPacket</td><td></td></tr>
|
||||
<tr><td>daveDebugByte</td><td></td></tr>
|
||||
<tr><td>daveDebugCompare</td><td></td></tr>
|
||||
<tr><td>daveDebugExchange</td><td></td></tr>
|
||||
<tr><td>daveDebugPDU</td><td>debug PDU handling</td></tr>
|
||||
<tr><td>daveDebugUpload</td><td>debug PDU loading program blocks from PLC</td></tr>
|
||||
<tr><td>daveDebugMPI</td><td></td></tr>
|
||||
<tr><td>daveDebugPrintErrors</td><td>Print error messages</td></tr>
|
||||
<tr><td>daveDebugPassive</td><td></td></tr>
|
||||
<tr><td>daveDebugAll</td><td>Enables all debug levels</td></tr>
|
||||
</table>
|
||||
<H2>Global variables</H2>
|
||||
<H3>Current debug level:</H3>
|
||||
<pre>
|
||||
int daveDebug;
|
||||
</pre>
|
||||
<H3>Set the Current debug level:</H3>
|
||||
<pre>
|
||||
void setDebug(int nDebug);
|
||||
</pre>
|
||||
<H3>Some useful data types:</H3>
|
||||
<pre>
|
||||
#define uc unsigned char
|
||||
#define us unsigned short
|
||||
#define u32 unsigned int
|
||||
</pre>
|
||||
typedef struct _daveConnection daveConnection;
|
||||
typedef struct _daveInterface daveInterface;
|
||||
<H3>Helper struct to manage PDUs. This is NOT the part of the packet called PDU, but a set of pointers that ease access to the "private parts" of a PDU.</H3>
|
||||
<pre>
|
||||
typedef struct {
|
||||
uc * header; /* pointer to start of PDU (PDU header) */
|
||||
uc * param; /* pointer to start of parameters inside PDU */
|
||||
uc * data; /* pointer to start of data inside PDU */
|
||||
uc * udata; /* pointer to start of result data inside PDU */
|
||||
int hlen; /* header length */
|
||||
int plen; /* parameter length */
|
||||
int dlen; /* data length */
|
||||
int udlen; /* user or result data length */
|
||||
} PDU;
|
||||
</pre>
|
||||
<H3>Definitions of prototypes for the protocol specific functions. The library "switches" protocol by setting pointers to the protol specific implementations.</H3>
|
||||
<pre>
|
||||
typedef int (*_initAdapterFunc) ();
|
||||
typedef int (*_connectPLCFunc) ();
|
||||
typedef int (*_disconnectPLCFunc) ();
|
||||
typedef int (*_disconnectAdapterFunc) ();
|
||||
typedef int (*_exchangeFunc) (daveConnection *, PDU *);
|
||||
typedef int (*_receiveFunc) (daveConnection *, PDU *);
|
||||
typedef int (*_listReachablePartnersFunc) (daveInterface * di, char * buf);
|
||||
</pre>
|
||||
/+
|
||||
This groups an interface together with some information about it's properties
|
||||
in the library's context.
|
||||
*/
|
||||
<pre>
|
||||
struct _daveInterface {
|
||||
_daveOSserialType fd; /* some handle for the serial interface */
|
||||
int users; /* a counter used when multiple PLCs are accessed via */
|
||||
/* the same serial interface and adapter. */
|
||||
int localMPI; /* the adapter's MPI address */
|
||||
char * name; /* just a name that can be used in programs dealing with multiple */
|
||||
/* daveInterfaces */
|
||||
int timeout; /* Timeout in microseconds used in transort. */
|
||||
int protocol; /* The kind of transport protocol used on this interface. */
|
||||
int speed; /* The MPI or Profibus speed */
|
||||
int ackPos; /* position of some packet number that has to be repeated in ackknowledges */
|
||||
_initAdapterFunc initAdapter; /* pointers to the protocol */
|
||||
_connectPLCFunc connectPLC; /* specific implementations */
|
||||
_disconnectPLCFunc disconnectPLC; /* of these functions */
|
||||
_disconnectAdapterFunc disconnectAdapter;
|
||||
_exchangeFunc exchange;
|
||||
_listReachablePartnersFunc listReachablePartners;
|
||||
};
|
||||
</pre>
|
||||
daveInterface * daveNewInterface(_daveOSserialType nfd, char * nname, int localMPI, int protocol, int speed);
|
||||
|
||||
/*
|
||||
A special header for MPI packets:
|
||||
*/
|
||||
<pre>
|
||||
typedef struct {
|
||||
uc src_conn;
|
||||
uc dst_conn;
|
||||
uc MPI;
|
||||
uc localMPI;
|
||||
uc len;
|
||||
uc func;
|
||||
uc packetNumber;
|
||||
} MPIheader;
|
||||
</pre>
|
||||
/*
|
||||
This is the packet header used by IBH ethernet NetLink.
|
||||
*/
|
||||
<pre>
|
||||
typedef struct {
|
||||
uc ch1; // logical connection or channel ?
|
||||
uc ch2; // logical connection or channel ?
|
||||
uc len; // number of bytes counted from the ninth one.
|
||||
uc packetNumber; // a counter, response packets refer to request packets
|
||||
us sFlags; // my guess
|
||||
us rFlags; // my interpretation
|
||||
} IBHpacket;
|
||||
</pre>
|
||||
|
||||
/*
|
||||
This holds data for a PLC connection;
|
||||
*/
|
||||
<pre>
|
||||
struct _daveConnection {
|
||||
daveInterface * iface; /* pointer to used interface */
|
||||
int MPIAdr; /* The PLC's address */
|
||||
int messageNumber; /* current message number */
|
||||
int needAckNumber; /* message number we need ackknowledge for */
|
||||
int AnswLen; /* length of last message */
|
||||
PDU rcvdPDU;
|
||||
MPIheader templ; /* template of MPI Header, setup once, copied in and then modified */
|
||||
uc msgIn[daveMaxRawLen];
|
||||
uc msgOut[daveMaxRawLen];
|
||||
uc * resultPointer; /* used to retrieve single values from the result byte array */
|
||||
uc * _resultPointer;
|
||||
uc packetNumber; /* packetNumber in transport layer */
|
||||
int PDUstartO; /* position of PDU in outgoing messages. This is different for different transport methodes. */
|
||||
int PDUstartI; /* position of PDU in incoming messages. This is different for different transport methodes. */
|
||||
int rack; /* rack number for ISO over TCP */
|
||||
int slot; /* slot number for ISO over TCP */
|
||||
int maxPDUlength;
|
||||
uc ackByte2;
|
||||
};
|
||||
</pre>
|
||||
/*
|
||||
Setup a new connection structure using an initialized
|
||||
daveInterface and PLC's MPI address.
|
||||
*/
|
||||
<pre>
|
||||
daveConnection * daveNewConnection(daveInterface * di, int MPI,int rack, int slot);
|
||||
</pre>
|
||||
<pre>
|
||||
typedef struct {
|
||||
uc type[2];
|
||||
unsigned short count;
|
||||
} daveBlockTypeEntry;
|
||||
</pre>
|
||||
<pre>
|
||||
typedef struct {
|
||||
unsigned short number;
|
||||
uc type[2];
|
||||
} daveBlockEntry;
|
||||
</pre>
|
||||
<pre>
|
||||
typedef struct {
|
||||
uc type[2];
|
||||
uc x1[2]; /* 00 4A */
|
||||
uc w1[2]; /* some word var? */
|
||||
char pp[2]; /* allways 'pp' */
|
||||
uc x2[4]; /* 00 4A */
|
||||
unsigned short number; /* the block's number */
|
||||
uc x3[26]; /* ? */
|
||||
unsigned short length; /* the block's length */
|
||||
uc x4[16];
|
||||
uc name[8];
|
||||
uc x5[12];
|
||||
} daveBlockInfo;
|
||||
</pre>
|
||||
<H2>PDU handling functions:</H2>
|
||||
PDU is the central structure present in S7 communication.
|
||||
It is composed of a 10 or 12 byte header,a parameter block and a data block.
|
||||
When reading or writing values, the data field is itself composed of a data
|
||||
header followed by payload data
|
||||
<pre>
|
||||
typedef struct {
|
||||
uc P; /* allways 0x32 */
|
||||
uc type; /* Header type, one of 1,2,3 or 7. type 2 and 3 headers are two bytes longer. */
|
||||
uc a,b; /* currently unknown. Maybe it can beused for long numbers? */
|
||||
us number; /* A number. This can be used to make sure a received answer */
|
||||
/* corresponds to the request with the same number. */
|
||||
us plen; /* length of parameters which follow this header */
|
||||
us dlen; /* length of data which follow the parameters */
|
||||
uc result[2]; /* only present in type 2 and 3 headers. This contains error information. */
|
||||
} PDUHeader;
|
||||
<pre>
|
||||
<H3>set up the PDU header.</H3> Needs valid header pointer in the struct p points to.
|
||||
<pre>
|
||||
void _daveInitPDUheader(PDU * p, int type);
|
||||
</pre>
|
||||
<H3>Add parameters after header</h3>
|
||||
Adjust pointer to data. needs valid header.
|
||||
<pre>
|
||||
void _daveAddParam(PDU * p,uc * param,us len);
|
||||
</pre>
|
||||
<H3>add data after parameters</H3>
|
||||
Set dlen needs valid header,and valid parameters.
|
||||
<pre>
|
||||
void _daveAddData(PDU * p,void * data,int len);
|
||||
</pre>
|
||||
<H3>Add values after value header in data</H3>
|
||||
Adjust dlen and data count. Needs valid header,parameters,data,dlen
|
||||
<pre>
|
||||
void _daveAddValue(PDU * p,void * data,int len);
|
||||
</pre>
|
||||
<H3>Add data in user data.</H3>
|
||||
Add a user data header, if not yet present.
|
||||
<pre>
|
||||
void _daveAddUserData(PDU * p, uc * da, int len);
|
||||
</pre>
|
||||
<H3>Build PDU for a read request</H3>
|
||||
<pre>
|
||||
void _daveConstructReadRequest(PDU *p, int area, int DBnum, int start, int bytes);
|
||||
</pre>
|
||||
<H3>
|
||||
build PDU for a BIT read request
|
||||
</H3>
|
||||
<pre> void _daveConstructBitReadRequest(PDU *p, int area, int DBnum, int start, int bytes);</pre>
|
||||
<H3>
|
||||
build the PDU for a write request
|
||||
</H3>
|
||||
<pre> void _daveConstructWriteRequest(PDU *p, int area, int DBnum, int start, int bytes,void * values);</pre>
|
||||
<H3>
|
||||
build the PDU for a bit write request
|
||||
</H3>
|
||||
<pre> void _daveConstructBitWriteRequest(PDU *p, int area, int DBnum, int start, int bytes,void * values);</pre>
|
||||
<H3>
|
||||
set up pointers to the fields of a received message
|
||||
<H3>
|
||||
<pre> int _daveSetupReceivedPDU(daveConnection * dc,PDU * p);</pre>
|
||||
<H3>
|
||||
send PDU to PLC and retrieves the answer
|
||||
</H3>
|
||||
<pre> int _daveExchange(daveConnection * dc,PDU *p);</pre>
|
||||
<H2>Utilities:<H2>
|
||||
<H3>Hex dump PDU:</H3>
|
||||
<pre> void _daveDumpPDU(PDU * p);</pre>
|
||||
<H3>Compare blocks:</H3>
|
||||
This is an extended memory compare routine. It can handle don't care and stop flags
|
||||
in the sample data. A stop flag lets it return success, if there were no mismatches
|
||||
up to this point.
|
||||
<pre> int _daveMemcmp(us * a, uc *b, size_t len);</pre>
|
||||
<H3>Hex dump:</H3>
|
||||
Writes the name followed by len bytes written in hex and a newline.
|
||||
<pre> void _daveDump(char * name,uc*b,int len);</pre>
|
||||
<H2>names for Objects</H2>
|
||||
<pre> char * daveBlockName(uc bn);</pre>
|
||||
<pre> char * daveAreaName(uc n);</pre>
|
||||
<H2>
|
||||
Data conversion convenience functions:
|
||||
</H2>
|
||||
|
||||
<pre> int daveGetByte(daveConnection * dc);</pre>
|
||||
|
||||
<pre> float daveGetFloat(daveConnection * dc);</pre>
|
||||
|
||||
<pre> int daveGetInteger(daveConnection * dc);</pre>
|
||||
|
||||
<pre> unsigned int daveGetDWORD(daveConnection * dc);</pre>
|
||||
|
||||
<pre> unsigned int daveGetUnsignedInteger(daveConnection * dc);</pre>
|
||||
|
||||
<pre> unsigned int daveGetWORD(daveConnection * dc);</pre>
|
||||
|
||||
<pre> int daveGetByteat(daveConnection * dc, int pos);</pre>
|
||||
|
||||
<pre> unsigned int daveGetWORDat(daveConnection * dc, int pos);</pre>
|
||||
|
||||
<pre> unsigned int daveGetDWORDat(daveConnection * dc, int pos);</pre>
|
||||
|
||||
<pre> float daveGetFloatat(daveConnection * dc, int pos);</pre>
|
||||
|
||||
<pre> float toPLCfloat(float ff);</pre>
|
||||
|
||||
<pre> short daveSwapIed_16(short ff);</pre>
|
||||
|
||||
<pre> int daveSwapIed_32(int ff);</pre>
|
||||
<H2>Newer data conversion convenience functions:</H2>
|
||||
Newer conversion routines. As the terms WORD, INT, INTEGER etc have different meanings
|
||||
for users of different programming languages and compilers, I choose to provide a new
|
||||
set of conversion routines named according to the bit length of the value used. The 'U'
|
||||
or 'S' stands for unsigned or signed.
|
||||
<H3>Get a value from the position b points to</h3>
|
||||
B is typically a pointer to a buffer that has
|
||||
been filled with daveReadBytes:
|
||||
<pre> int daveGetS8from(uc *b);</pre>
|
||||
<pre> int daveGetU8from(uc *b);</pre>
|
||||
<pre> int daveGetS16from(uc *b);</pre>
|
||||
<pre> int daveGetU16from(uc *b);</pre>
|
||||
<pre> int daveGetS32from(uc *b);</pre>
|
||||
<pre> unsigned int daveGetU32from(uc *b);</pre>
|
||||
<pre> float daveGetFloatfrom(uc *b);</pre>
|
||||
<H3>Get a value from the current position</H3>
|
||||
in the last result read on the connection dc.
|
||||
This will increment an internal pointer, so the next value is read from the position
|
||||
following this value.
|
||||
|
||||
<pre> int daveGetS8(daveConnection * dc);</pre>
|
||||
<pre> int daveGetU8(daveConnection * dc);</pre>
|
||||
<pre> int daveGetS16(daveConnection * dc);</pre>
|
||||
<pre> int daveGetU16(daveConnection * dc);</pre>
|
||||
<pre> int daveGetS32(daveConnection * dc);</pre>
|
||||
<pre> unsigned int daveGetU32(daveConnection * dc);</pre>
|
||||
<H2>
|
||||
Get a value from a given position in the last result read on the connection dc.</h2>
|
||||
<pre> int daveGetS8at(daveConnection * dc, int pos);</pre>
|
||||
<pre> int daveGetU8at(daveConnection * dc, int pos);</pre>
|
||||
<pre> int daveGetS16at(daveConnection * dc, int pos);</pre>
|
||||
<pre> int daveGetU16at(daveConnection * dc, int pos);</pre>
|
||||
<pre> int daveGetS32at(daveConnection * dc, int pos);</pre>
|
||||
<pre> unsigned int daveGetU32at(daveConnection * dc, int pos);</pre>
|
||||
<H3>put one byte into buffer b:</H3>
|
||||
<pre> uc * davePut8(uc *b,int v);</pre>
|
||||
<pre> uc * davePut16(uc *b,int v);</pre>
|
||||
<pre> uc * davePut32(uc *b,int v);</pre>
|
||||
<pre> uc * davePutFloat(uc *b,float v);</pre>
|
||||
<pre> void davePut8at(uc *b, int pos, int v);</pre>
|
||||
<pre> void davePut16at(uc *b, int pos, int v);</pre>
|
||||
<pre> void davePut32at(uc *b, int pos, int v);</pre>
|
||||
<pre> void davePutFloatat(uc *b,int pos, float v);</pre>
|
||||
/**
|
||||
Timer and Counter conversion functions:
|
||||
**/
|
||||
/*
|
||||
get time in seconds from current read position:
|
||||
*/
|
||||
<pre> float daveGetSeconds(daveConnection * dc);</pre>
|
||||
/*
|
||||
get time in seconds from random position:
|
||||
*/
|
||||
<pre> float daveGetSecondsAt(daveConnection * dc, int pos);
|
||||
/*
|
||||
get counter value from current read position:
|
||||
*/
|
||||
<pre> int daveGetCounterValue(daveConnection * dc);
|
||||
/*
|
||||
get counter value from random read position:
|
||||
*/
|
||||
<pre> int daveGetCounterValueAt(daveConnection * dc,int pos);
|
||||
|
||||
/*
|
||||
Functions to load blocks from PLC:
|
||||
*/
|
||||
<pre> void _daveConstructUpload(PDU *p,char blockType, int blockNr);
|
||||
|
||||
<pre> void _daveConstructDoUpload(PDU * p, int uploadID);
|
||||
|
||||
<pre> void _daveConstructEndUpload(PDU * p, int uploadID);
|
||||
/*
|
||||
Get the PLC's order code as ASCIIZ. Buf must provide space for
|
||||
21 characters at least.
|
||||
*/
|
||||
|
||||
#define daveOrderCodeSize 21
|
||||
<pre> int daveGetOrderCode(daveConnection * dc,char * buf);
|
||||
/*
|
||||
connect to a PLC. returns 0 on success.
|
||||
*/
|
||||
|
||||
<pre> int daveConnectPLC(daveConnection * dc);
|
||||
/*
|
||||
Read len bytes from the PLC. Start determines the first byte.
|
||||
Area denotes whether the data comes from FLAGS, DATA BLOCKS,
|
||||
INPUTS or OUTPUTS. The reading and writing of other data
|
||||
like timers and counters is not supported.
|
||||
DB is the number of the data block to be used. Set it to zero
|
||||
for other area types.
|
||||
Buffer is a pointer to a memory block provided by the calling
|
||||
program. If the pointer is not NULL, the result data will be copied thereto.
|
||||
Hence it must be big enough to take up the result.
|
||||
In any case, you can also retrieve the result data using the get<type> macros
|
||||
on the connection pointer.
|
||||
|
||||
FIXME: Existence of DB is not checked.
|
||||
There is no error message for nonexistent data blocks.
|
||||
There is no check for max. message len or
|
||||
automatic splitting into multiple messages.
|
||||
*/
|
||||
|
||||
<pre> int daveReadBytes(daveConnection * dc, int area, int DB, int start, int len, void * buffer);
|
||||
/*
|
||||
Write len bytes from buffer to the PLC.
|
||||
Start determines the first byte.
|
||||
Area denotes whether the data goes to FLAGS, DATA BLOCKS,
|
||||
INPUTS or OUTPUTS. The writing of other data
|
||||
like timers and counters is not supported.
|
||||
DB is the number of the data block to be used. Set it to zero
|
||||
for other area types.
|
||||
FIXME: Existence of DB is not checked.
|
||||
There is no error message for nonexistent data blocks.
|
||||
There is no check for max. message len or
|
||||
automatic splitting into multiple messages.
|
||||
*/
|
||||
<pre> int daveWriteBytes(daveConnection * dc,int area, int DB, int start, int len, void * buffer);
|
||||
|
||||
/*
|
||||
Bit manipulation:
|
||||
*/
|
||||
<pre> int daveReadBits(daveConnection * dc, int area, int DB, int start, int len, void * buffer);
|
||||
<pre> int daveWriteBits(daveConnection * dc,int area, int DB, int start, int len, void * buffer);
|
||||
/*
|
||||
PLC diagnostic and inventory functions:
|
||||
*/
|
||||
<pre> int daveReadSZL(daveConnection * dc, int ID, int index, void * buf);
|
||||
<pre> int daveListBlocksOfType(daveConnection * dc,uc type,daveBlockEntry * buf);
|
||||
<pre> int daveListBlocks(daveConnection * dc,daveBlockTypeEntry * buf);
|
||||
/*
|
||||
PLC program read functions:
|
||||
*/
|
||||
<pre> int initUpload(daveConnection * dc,char blockType, int blockNr, int * uploadID);
|
||||
<pre> int doUpload(daveConnection*dc, int * more, uc**buffer, int*len, int uploadID);
|
||||
<pre> int endUpload(daveConnection*dc, int uploadID);
|
||||
/*
|
||||
Multiple variable support:
|
||||
*/
|
||||
typedef struct {
|
||||
int error;
|
||||
int length;
|
||||
uc * bytes;
|
||||
} daveResult;
|
||||
|
||||
typedef struct {
|
||||
int numResults;
|
||||
daveResult * results;
|
||||
} daveResultSet;
|
||||
|
||||
|
||||
/* use this to initialize a multivariable read: */
|
||||
<pre> void davePrepareReadRequest(daveConnection * dc, PDU *p);
|
||||
/* Adds a new variable to a prepared request: */
|
||||
<pre> void daveAddVarToReadRequest(PDU *p, int area, int DBnum, int start, int bytes);
|
||||
/* Executes the complete request. */
|
||||
<pre> int daveExecReadRequest(daveConnection * dc, PDU *p, daveResultSet * rl);
|
||||
/* Lets the functions daveGet<data type> work on the n-th result: */
|
||||
<pre> int daveUseResult(daveConnection * dc, daveResultSet rl, int n);
|
||||
/* Frees the memory occupied by the result structure */
|
||||
<pre> void daveFreeResults(daveResultSet * rl);
|
||||
|
||||
<pre> int daveInitAdapter(daveInterface * di);
|
||||
<pre> int daveConnectPLC(daveConnection * dc);
|
||||
<pre> int daveDisconnectPLC(daveConnection * dc);
|
||||
|
||||
<pre> int daveDisconnectAdapter(daveInterface * di);
|
||||
<pre> int daveListReachablePartners(daveInterface * di,char * buf);
|
||||
|
||||
<pre> int _daveInitAdapterDummy(daveInterface * di);
|
||||
<pre> int _daveConnectPLCDummy(daveConnection * dc);
|
||||
<pre> int _daveDisconnectPLCDummy(daveConnection * dc);
|
||||
<pre> int _daveDisconnectAdapterDummy(daveInterface * di);
|
||||
<pre> int _daveExchangeDummy(daveConnection * dc,PDU * p1);
|
||||
<pre> int _daveListReachablePartnersDummy(daveInterface * di,char * buf);
|
||||
|
||||
/* MPI specific functions */
|
||||
|
||||
#define daveMPIReachable 0x30
|
||||
#define daveMPIunused 0x10
|
||||
#define davePartnerListSize 126
|
||||
|
||||
<pre> int _daveListReachablePartnersMPI(daveInterface * di,char * buf);
|
||||
<pre> int _daveInitAdapterMPI1(daveInterface * di);
|
||||
<pre> int _daveInitAdapterMPI2(daveInterface * di);
|
||||
<pre> int _daveConnectPLCMPI1(daveConnection * dc);
|
||||
<pre> int _daveConnectPLCMPI2(daveConnection * dc);
|
||||
<pre> int _daveDisconnectPLCMPI(daveConnection * dc);
|
||||
<pre> int _daveDisconnectAdapterMPI(daveInterface * di);
|
||||
<pre> int _daveExchangeMPI(daveConnection * dc,PDU * p1);
|
||||
|
||||
/* ISO over TCP specific functions */
|
||||
<pre> int _daveExchangeTCP(daveConnection * dc,PDU * p1);
|
||||
<pre> int _daveConnectPLCTCP(daveConnection * dc);
|
||||
/*
|
||||
make internal PPI functions available for experimental use:
|
||||
*/
|
||||
<pre> int _daveExchangePPI(daveConnection * dc,PDU * p1);
|
||||
<pre> void _daveSendYOURTURN(daveConnection * dc);
|
||||
<pre> void _daveSendLength(daveInterface * di, int len);
|
||||
<pre> void _daveSendIt(daveInterface * di, uc * b, int size);
|
||||
<pre> int _daveReadChars(daveInterface * di, uc *b, int tmo, int max);
|
||||
|
||||
/*
|
||||
make internal MPI functions available for experimental use:
|
||||
*/
|
||||
<pre> int _daveReadMPI(daveInterface * di, uc *b);
|
||||
<pre> void _daveSendSingle(daveInterface * di, uc c);
|
||||
<pre> int _daveSendAck(daveConnection * dc, int nr);
|
||||
<pre> int _daveGetAck(daveInterface*di, int nr);
|
||||
<pre> int _daveSendDialog2(daveConnection * dc, int size);
|
||||
<pre> int _daveSendWithCRC(daveInterface * di, uc *b, int size);
|
||||
<pre> int _daveReadSingle(daveInterface * di);
|
||||
|
||||
<pre> int _daveReadOne(daveInterface * di, uc *b);
|
||||
|
||||
typedef uc * (*userReadFunc) (int , int, int, int, int *);
|
||||
typedef void (*userWriteFunc) (int , int, int, int, int *,uc *);
|
||||
extern userReadFunc readCallBack;
|
||||
extern userWriteFunc writeCallBack;
|
||||
|
||||
void _daveConstructReadResponse(PDU * p);
|
||||
void _daveConstructWriteResponse(PDU * p);
|
||||
void _daveConstructBadReadResponse(PDU * p);
|
||||
void _daveHandleRead(PDU * p1,PDU * p2);
|
||||
void _daveHandleWrite(PDU * p1,PDU * p2);
|
||||
//void _daveSendMPIAck2(daveConnection *dc);
|
||||
|
||||
#endif /* _nodave */
|
||||
|
||||
|
||||
/*
|
||||
Changes:
|
||||
07/19/04 added the definition of daveExchange().
|
||||
09/09/04 applied patch for variable Profibus speed from Andrew Rostovtsew.
|
||||
09/09/04 applied patch from Bryan D. Payne to make this compile under Cygwin and/or newer gcc.
|
||||
12/09/04 added daveReadBits(), daveWriteBits()
|
||||
12/09/04 added some more comments.
|
||||
12/09/04 changed declaration of _daveMemcmp to use typed pointers.
|
||||
*/
|
||||
150
doc/gettingStarted.html
Normal file
150
doc/gettingStarted.html
Normal file
@@ -0,0 +1,150 @@
|
||||
<H1>Getting started</H1>
|
||||
<H2>Using the test programs</H2>
|
||||
<H3>Intended purpose</H3>
|
||||
<b>Libnodave</b> comes with a set of test programs. They shall serve the following purposes:
|
||||
<li>Provide the user with a demostration of what Libnodave can do.</li>
|
||||
<li>Provide a quick test for compatibility with user's hardware and configuration.</li>
|
||||
<li>Provide a source code example as a template for your own applications.</li>
|
||||
<li>The debug output, obtained with debug option (-d), provides valuable informatioon in case Libnodave fails with some hardware..</li>
|
||||
<li>The benchmark options let you measure the time needed for transfers of short and long data blocks.</li>
|
||||
<H4>Note on PASCAL source test programs:</H3>
|
||||
Basic test programs are also available as Pascal sources. They are not as complete as their
|
||||
C coded counterparts. Their main purpose is to test the interface unit <b>nodave.pas</b>.
|
||||
<H3>Calling test programs</H3>
|
||||
Just invoke the test programs without arguments.
|
||||
They will print a list of possible arguments and options.
|
||||
<H3>Which test program for which Setup?</H3>
|
||||
<table border=1>
|
||||
<tr><th>CPU</th><th>Connection</th><th>Generell Tests</th><th>Load Program into CPU</th></tr>
|
||||
<tr><th>S7 300 or 400</th><th>Serial with MPI adapter cable</th><th>testMPI</th><th>testMPIload</th></tr>
|
||||
<tr><th>S7 200</th><th>Serial with PPI adapter cable</th><th>testPPI</th><th>testPPIload</th></tr>
|
||||
<tr><th>S7 300 or 400</th><th>Ethernet CP343/443</th><th>testISO_TCP</th><th>testISO_TCPload</th></tr>
|
||||
<tr><th>S7 200</th><th>Ethernet CP243</th><th>testISO_TCP -2</th><th>testISO_TCPload -2</th></tr>
|
||||
<tr><th>S7 300 or 400</th><th>Ethernet with IBH/MHJ-NetLink Gateway</th><th>testIBH</th><th>testMPI_IBHload</th></tr>
|
||||
<tr><th>S7 200</th><th>Ethernet with IBH/MHJ-NetLink Gateway</th><th>testPPI_IBH</th><th>testPPI_IBHload</th></tr>
|
||||
</table>
|
||||
<H3>Options to make test programs work with certain configurations:</H3>
|
||||
<H4>MPI transport with MPI adapter:</H4>
|
||||
<li>--mpi=[number] Uses number as the MPI address of the PLC. Default is 2.</li>
|
||||
<li>--local=[number] Uses number as the local MPI address of the adapter. Default is 0.</li>
|
||||
<li>-2 Uses another variant of the MPI protocol. Try if you connect to adapter/PLC.</li>
|
||||
<li>-[some numbers] Use dfferent MPI/Profibus speeds.</li>
|
||||
<H4>ISO over TCP transport with CP343/CP443:</H4>
|
||||
<li>--slot=[number] Uses number as the slot address of the PLC. Default rack 0, slot 2.</li>
|
||||
<H4>ISO over TCP transport with CP243:</H4>
|
||||
<li>-2 Fakes a MicroWin connection request. This is currently mandatory for CP243.
|
||||
It will switch the CFG LED on.</li>
|
||||
<H3>What can the test programs do?</H3>
|
||||
If invoked with the connection as the only argument, all test programs will read some data from
|
||||
the memory area of Flags (also known as Merkers).They try to read FD0,FD4 and FD8 as DWORDS and
|
||||
FD12 as real.<br>Depending on the contents of this memory, the results may or may no seem
|
||||
reasonable.The obtained values are just the same as if you would observe these variables in Step7
|
||||
using the display formats signed,signed,signed and floating point.<br>
|
||||
If you specify the option -w, the test programs increment the data, write it back to your PLC
|
||||
<font color=red>(Attention! This changes PLC internal memory!)</font> and read it again, thus demonstrating the effect of
|
||||
changes.<br>
|
||||
If you specify the option -c, the test programs write 0 to these memory locations. <font color=red>
|
||||
(Attention! This changes PLC internal memory!)</font>. This is useful if the current memory contents
|
||||
doesn't make much sense when displayed in the above mentioned format.<br>
|
||||
If you specify the option -b, the test programs try to do block read benchmark tests. Combining -b and
|
||||
-w will also do write benchmark tests.<br>
|
||||
-r option tries to put your PLC into RUN mode.<font color=red>(Attention! May start actions on machinery!).</font><br>
|
||||
-s option tries to put your PLC into STOP mode.<font color=red>(Attention! Will interrupt running machinery!).</font><br>
|
||||
--readout option tries to readout program blocks from the PLC and will store them in files named
|
||||
like OB1.mc7.<font color=red>(Attention! I got reports, that this produces ill effects on S7-400!).</font><br>
|
||||
-z reads System State Lists (<b>S</b>ystem-<b>Z</b>ustands<b>l</b>isten from the PLC. These lists exist
|
||||
only in 300/400 family PLCs and provide diagnostic information. Please refer to Siemens documentation about
|
||||
the meaning of IDs and indices.<br>
|
||||
<H3>Test programs to load blocks into CPU</H3>
|
||||
<li>This is a quite experimental feature.
|
||||
First you will need correctly formed program blocks stored in files. A possible source are files
|
||||
previously read out using --readout. You cannot get them from Step7 as Step7 stores program
|
||||
block in a data base. It has not been tested but may be so that third party programming software
|
||||
that stores program blocks in files uses the same file format.<br>
|
||||
Loading of SDBs (<b>S</b>ystem <b>D</b>ata <b>B</b>locks) is highly dependent of the sequence of
|
||||
block numbers.
|
||||
<H2>Programming a basic application</H2>
|
||||
<H4>Preparations</H4>
|
||||
The main purpose of this library is to read and write data from and to Siemens PLCs.
|
||||
To do so, you need to establish a connection to the PLC.
|
||||
First, you need to configure a serial port of your computer or establish a TCP connection.
|
||||
This connection is represented by the type _daveOSserialType, which contains file descriptors
|
||||
in case of Unix-like systems, handles in case of windows and what other systems supported in
|
||||
the future might use for this purpose.
|
||||
|
||||
use setport to initialize the members of a <a href=daveOSserialType.html>_daveOSserialType</a> to something representing
|
||||
a configured serial connection:
|
||||
<pre>
|
||||
fds.rfd=<a href=setport.html>setPort</a>(argv[adrPos],"38400",'O');
|
||||
</pre>
|
||||
for serial connections or:
|
||||
<pre>
|
||||
fds.rfd=<a href=openSocket.html>openSocket</a>(102, IPaddress_of_CP);
|
||||
</pre>
|
||||
or
|
||||
<pre>
|
||||
fds.rfd=<a href=openSocket.html>openSocket</a>(1099, IPaddress_of_IBH-NetLink);
|
||||
</pre>
|
||||
for TCP connections. Then do:
|
||||
<pre>
|
||||
fds.wfd=fds.rfd;
|
||||
</pre>
|
||||
With the initialized _daveOSserialType, you will initialize a structure of type
|
||||
<a href=daveInterface.html>daveInterface</a>,
|
||||
representing the physical connection to a PLC or a network of PLCs (e.g. like MPI).
|
||||
<pre>
|
||||
di=<a href=daveInterface.html>daveNewInterface</a>(fds, "IF1", localMPI, daveProtoXXX, daveSpeedYYY);
|
||||
</pre>
|
||||
With the resulting daveInterface structure, you can initialize an adapter, if one is used:
|
||||
<pre>
|
||||
res =daveInitAdapter(di);
|
||||
</pre>
|
||||
While currently only MPI-adapters and IBH-NetLinks really need this initialization procedure, it is save to use
|
||||
daveInitAdapter() with any protocol type. If it has no meaning for the protocol used, it is
|
||||
mapped to a dummy procedure that returns allways success.
|
||||
|
||||
After successfully initializing your adapter, you can retrieve a list of reachable partners
|
||||
on an MPI network. The function takes the daveInterface structure and a pointer to a buffer
|
||||
of sufficient length as arguments. It returns the real length of the list. If the partners cannot
|
||||
be listed with the protocol used, it just returns a length of 0.
|
||||
<pre>
|
||||
listLength = daveListReachablePartners(di,buf1);
|
||||
</pre>
|
||||
After successfully initializing your adapter, you can establish a connection to a certain PLC
|
||||
on the network. To do so, you will first initialize a structure of
|
||||
type <a href=daveConnection.html>daveConnection</a>,
|
||||
representing the logical connection to a single PLC.
|
||||
<pre>
|
||||
dc =daveNewConnection(di, MPI_address, Rack, Slot);
|
||||
</pre>
|
||||
With the resulting daveConnection structure, you need to really connect the PLC:
|
||||
<pre>
|
||||
res =daveConnectPLC(dc);
|
||||
</pre>
|
||||
<H4>Exchanging values:</H4>
|
||||
Once you have established a connection to your PLC, you can read and write values:
|
||||
<pre>
|
||||
res=<a href=daveReadBytes.html>daveReadBytes</a>(dc, <a href=area.html>AREA</a>, area_Number, start_address, length, buffer);
|
||||
</pre>
|
||||
<pre>
|
||||
res=<a href=daveWriteBytes.html>daveWriteBytes</a>(dc, <a href=area.html>AREA</a>, area_Number, start_address, length, buffer);
|
||||
</pre>
|
||||
Usually, you will have to <a href=conversions.html>convert</a> byte sequences from and to the buffer
|
||||
to use the data in your application.<br>
|
||||
After you are done with your data exchanges, call:
|
||||
<pre>
|
||||
daveDisconnectPLC(dc);
|
||||
</pre>
|
||||
To disconnect from the PLC and
|
||||
<pre>
|
||||
daveDisconnectAdapter(di);
|
||||
</pre>
|
||||
to disconnect from the Adapter.
|
||||
Now close the serial or TCP/IP connection using the appropriate system calls for your OS.
|
||||
<H1>Advanced data exchange</H1>
|
||||
<a href=readmultiple.html>Read multiple items with a single transaction.</a><br>
|
||||
<a href=bitfunctions.html>Read and set single bits.</a><br>
|
||||
<H1>Other features</H1>
|
||||
<a href=SZL.html>Read diagnostic info (300 and 400 only).</a><br>
|
||||
<a href=upload.html>Load program code from PLC.</a><br>
|
||||
<a href=upload.html>Load program code into PLC.</a><br>
|
||||
23
doc/index.html
Normal file
23
doc/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta content="">
|
||||
<style></style>
|
||||
</head>
|
||||
<body>
|
||||
<H1>The beginnings of a documentation for <b>LIBNODAVE</b></H1>
|
||||
<H2>Purpose</H2>
|
||||
LIBNODAVE provides a way to exchange data with Siemens PLCs of S7-200, 300 and 400 families. It has also been successfully tested with a <a href="http://www.vipa.de">VIPA</a> Speed7 CPU. It should also be useable with S7-compatible PLCs from SAIA.<br>
|
||||
Data exchange comprises all memory areas and variables you canaccess in your PLC programs, e.g. flags, data blocks,input and output image memory, timers and counters.<br>
|
||||
Additionally, <b>LIBNODAVE</b>provides access to functions that are in the scope of programming software, e,g. reading diagnostic information, read program blocks from a PLC and write them to a PLC, start and stop a PLC.
|
||||
<H2>Licensing</H2>
|
||||
<b>LIBNODAVE</b> is free software under GPL and LGPL.
|
||||
<H2>Availability</H2>
|
||||
<b>LIBNODAVE</b> is currently available for UNIX and Win32. It comes with precompiled libraries for LINUX and Windows. You may port it yourself on any system providing a C compiler.<br>
|
||||
Get the latest version from <a href="http://libnodave.sf.net">Sourceforge</a>.
|
||||
<H2>Basic usage</H2>
|
||||
<a href=gettingStarted.html>getting started</a>
|
||||
<H2>FAQ</H2>
|
||||
<a href=FAQ.html>frequently asked questions</a>
|
||||
</body>
|
||||
</html>
|
||||
9
doc/initAdapter.html
Normal file
9
doc/initAdapter.html
Normal file
@@ -0,0 +1,9 @@
|
||||
With the resulting daveInterface structure, you need to initialize an adapter, if one is used:
|
||||
<pre>
|
||||
res =daveInitAdapter(di);
|
||||
</re>
|
||||
While currently only MPI-adapters really need this initialization procedure, it is save to use
|
||||
daveInitAdapter() with any protocol type. If it has no meaning for the protocol used, it is
|
||||
mapped to a dummy procedure that returns allways success.
|
||||
|
||||
After successfully initializing your adapter, you can retrieve a list of reachable partners
|
||||
13
doc/multiplePLCs.html
Normal file
13
doc/multiplePLCs.html
Normal file
@@ -0,0 +1,13 @@
|
||||
If you want to use more than one PLC on an MPI network, you would have to do:
|
||||
<pre>
|
||||
dc2 =daveNewConnection(di, 2nd_MPI_address, 0, 0);
|
||||
res =daveConnectPLC(dc2);
|
||||
</pre>
|
||||
If you want to use more than one PLC over TCP connections, you would have to setup a second
|
||||
daveOSserialType, daveInterface and daveConnection:
|
||||
<pre>
|
||||
fds2.rfd=openSocket(102, IPaddress_of_CP);
|
||||
di2 =daveNewInterface(fds2, "IF2", 0, daveProtoISO_TCP, 0);
|
||||
dc2 =daveNewConnection(di2, 0, 0, 2);
|
||||
res =daveConnectPLC(dc2);
|
||||
</pre>
|
||||
14
doc/openSocket.html
Normal file
14
doc/openSocket.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<H1>openSocket</H1>
|
||||
An OS specific routine to establish a TCP/IP connection to a partner.
|
||||
There are different implementations for LINUX and WIN32.
|
||||
While the OS specific implementation of openSocket() is part of LIBNODAVE dynamic library,
|
||||
you could use your own routine and copy the resulting file descriptor/handle to the
|
||||
members of your <a href=daveOSserialType.html>_daveOSserialType</a> structure.
|
||||
<pre>
|
||||
int openSocket(const int port, const char * peer);
|
||||
</pre>
|
||||
<li>port is the port number for the protocol, usually 102 for ISO over TCP or 1099 for the IBH/MHJ NetLink protocol.</li>
|
||||
<li>peer is the IP address of the PLC/CP as a string, e.g. 192.168.0.3 .</li>
|
||||
<h3>Note:</h3>
|
||||
With regard to <b>Libnodave</b>, you are free to use other port numbers. While you cannot change port numbers on S7 devices or IBH NetLinks, this can be useful with port redirecting software like <br>rinetd</b>, which makes a gateway listen on several ports and then redirects connections to other IP adresses.<br>
|
||||
This is the reason, why default port numbers are not hard coded in <b>Libnodave</b>.
|
||||
62
doc/pdu.html
Normal file
62
doc/pdu.html
Normal file
@@ -0,0 +1,62 @@
|
||||
<H1>PDU (protocol data unit)</H1>
|
||||
This is the central part of packets exchanged in S7-Communication. A PDU cosists of:
|
||||
<li>A 10 or 12 byte header</li>
|
||||
<li>A parameter area</li>
|
||||
<li>A data area</li>
|
||||
Header:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>0</td><td>allways 0x32</td></tr>
|
||||
<tr><td>1</td><td>type</td><td>1,2,3 or 7</td></tr>
|
||||
<tr><td>2,3</td><td>unknown</td><td>0</td></tr>
|
||||
<tr><td>4,5</td><td>sequence number</td><td></td></tr>
|
||||
<tr><td>6,7</td><td>length of parameters</td><td></td></tr>
|
||||
<tr><td>8,9</td><td>length of data</td><td></td></tr>
|
||||
<tr><td>10,11</td><td>error code</td><td></td></tr>
|
||||
</table>
|
||||
Parameters:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>0</td><td>a function number</td></tr>
|
||||
<tr><td>rest</td><td>depends on function number</td><td></td></tr>
|
||||
</table>
|
||||
Data:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>rest</td><td>depends on function number</td><td></td></tr>
|
||||
</table>
|
||||
Parameters for read request:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>0</td><td>function number for read</td><td>4</td></tr>
|
||||
<tr><td>1</td><td>number of items to read</td><td>1..20</td></tr>
|
||||
<tr><td>2..</td><td>item adresses, 12 byte each</td><td></td></tr>
|
||||
</table>
|
||||
Forming the item address:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>0,1,2</td><td>unknown</td><td>allways 0x12, 0x0a, 0x10</td></tr>
|
||||
<tr><td>3</td><td>transport size or unit size</td><td>1=single bit, 2=byte, 4=word</td></tr>
|
||||
<tr><td>4,5</td><td>length in byte</td><td></td></tr>
|
||||
<tr><td>6,7</td><td>number of data block</td><td>0 for ares other than data block</td></tr>
|
||||
<tr><td>8</td><td>area code</td><td>see area</td></tr>
|
||||
<tr><td>9,10,11</td><td>Start address in bits.</td><td>multiples of 8, if unit size is not bits</td></tr>
|
||||
</table>
|
||||
read response:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>0</td><td>function number for read</td><td>4</td></tr>
|
||||
<tr><td>1</td><td>number read items</td><td>1..20</td></tr>
|
||||
<tr><td>2..</td><td>items, 4 byte "data header" +data each</td><td></td></tr>
|
||||
</table>
|
||||
Data header:
|
||||
<table>
|
||||
<tr><th>Position</th><th>meaning</th><th>possible values</th></tr>
|
||||
<tr><td>0</td><td>return code</td><td>0xFF means ok, data follows after this header. Other codes give reasons why no data is returned.</td></tr>
|
||||
<tr><td>1</td><td>transport size or unit size</td><td>4=single bit, 9=byte</td></tr>
|
||||
<tr><td>2,3</td><td>length in bits</td><td></td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
51
doc/readmultiple.html
Normal file
51
doc/readmultiple.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<H1>Read multiple items</H1>
|
||||
The purpose of this mechanism ist to read multiple blocks of bytes from different start addresses and/or memory
|
||||
areas with a single request to the PLC.
|
||||
<H2>Basics:</H2>
|
||||
First, you have to prepare an "empty" read request, i.e. one that doesn't contain the address of an
|
||||
item. You need a variable of type PDU to store the request. To this request, you add the desired
|
||||
items using the same parameters you would specify to <a href=daveReadBytes.html> daveReadBytes</a>.
|
||||
You may add up to 20 difeerent items (limit introduced by Siemens PLCs) provided that the result
|
||||
data fits into a single response PDU. When you have added all desired items, call
|
||||
daveExecReadRequest which performs the actual data exchange with the PLC. Example:
|
||||
<pre>
|
||||
PDU p;
|
||||
daveResultSet rs;
|
||||
davePrepareReadRequest(dc, &p);
|
||||
daveAddVarToReadRequest(&p,daveInputs,0,0,1);
|
||||
daveAddVarToReadRequest(&p,daveFlags,0,0,4);
|
||||
daveAddVarToReadRequest(&p,daveDB,6,20,2);
|
||||
daveAddVarToReadRequest(&p,daveFlags,0,12,2);
|
||||
res=daveExecReadRequest(dc, &p, &rs);
|
||||
</pre>
|
||||
Now the daveResultSet should contain a result for each item. Each result contains error information,
|
||||
length information and the resulting byte array. You can use these results in two ways: Either
|
||||
access the structure daveResult directly or use:
|
||||
</pre>
|
||||
daveUseResult(daveConnection *, daveResultSet * rs, int number);
|
||||
</pre>
|
||||
This will set the internal result pointer of the <a href=daveConnection.html>daveConnection</a>
|
||||
to the result byte array. After doing this, the normal <a href=conversions.html>conversion functions</a> can be used
|
||||
to transfer single values to C variables. Example:
|
||||
<pre>
|
||||
res=daveUseResult(dc, rs, 0); // first result
|
||||
if (res==0) {
|
||||
a=daveGetU8(dc);
|
||||
printf("%d\n",a);
|
||||
} else
|
||||
printf("*** Error: %s\n",daveStrerror(res));
|
||||
</pre>
|
||||
<pre>
|
||||
res=daveUseResult(dc, rs, 1); // 2nd result
|
||||
if (res==0) {
|
||||
a=daveGetInteger(dc);
|
||||
printf("%d\n",a);
|
||||
} else
|
||||
printf("*** Error: %s\n",daveStrerror(res));
|
||||
</pre>
|
||||
If you do not need the results any more, call:
|
||||
<pre>
|
||||
daveFreeResults(&rs);
|
||||
</pre>
|
||||
This will free the memory occupied by the single results (but not by the resultSet itself),
|
||||
leaving you with an empty reultSet that can be reused in the next multi item read.
|
||||
13
doc/setport.html
Normal file
13
doc/setport.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<H1>setport</H1>
|
||||
An OS specific routine to configure and open a serial port.
|
||||
There are different implementations for LINUX and WIN32.
|
||||
While the respective implementation of setport() is part of LIBNODAVE dynamic library,
|
||||
you could use your own routine and copy the resulting filedescriptor/handle to the
|
||||
members of your <a href=daveOSserialType.html>_daveOSserialType</a> structure.
|
||||
<pre>
|
||||
int setPort(char * name, char* baud,char parity);
|
||||
</pre>
|
||||
<H4>Parameters:</H4>
|
||||
<li>name: The name of the serial port known to the OS, e.g. COM1 or /dev/ttyS0.</li>
|
||||
<li>baud: A baudrate.</li>
|
||||
<li>parity: One of the letters E,e,O,o,N or n meaning even, odd or none.</li>
|
||||
73
doc/speedissues.html
Normal file
73
doc/speedissues.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<H1>Conversion routines</H1>
|
||||
The buffers used by daveReadBytes() and daveWriteBytes() will contain a copy of the PLC memory area. This means: If you read from the beginning of DB2, the buffer will contain a byte for byte copy of DB2. The values are the same and in the same order, as what you get when you observe byte variables in Step7. Example:<br>
|
||||
<table>
|
||||
<tr><td>DB20.DBB0</td><td>26</td></tr>
|
||||
<tr><td>DB20.DBB1</td><td>37</td></tr>
|
||||
<tr><td>DB20.DBB2</td><td>48</td></tr>
|
||||
<tr><td>DB20.DBB3</td><td>15</td></tr>
|
||||
<tr><td>DB20.DBB4</td><td>16</td></tr>
|
||||
<table>
|
||||
You are free to interpret these values as single bytes or multibyte values,the same way as you can do this in Step7 AWL.:<br>
|
||||
Also it is unusual, you can load a real value from DB20.DBD1:<br>
|
||||
<pre>
|
||||
L DB20.DBD1
|
||||
L 2.0
|
||||
*R
|
||||
</pre>
|
||||
A further complication results from the fact that Siemens PLCs store multibyte values beginning with the most significant byte (big endian) while Intel based PCs store the least significant byte first (little endian).<br>
|
||||
It is not possible to convert the byte order in the daveReadBytes() or daveWriteBytes() fuctions
|
||||
because the start position of each multibyte value is not known then.<br>
|
||||
You are free to place such values at arbitrary byte addresses in your PLC program.
|
||||
The same adresses must in turn be used to retrieve values from the copy of PLC memory.
|
||||
If you have a data block DB2 with the following layout:<br>
|
||||
<table>
|
||||
<tr><td>DBB 0</td><td>BYTE</td></tr>
|
||||
<tr><td>DBD 1</td><td>DWORD</td></tr>
|
||||
<tr><td>DBD 5</td><td>REAL</td></tr>
|
||||
</table>
|
||||
You can retrieve the single values in three ways:<br>
|
||||
1. From the intenal buffer. After a successful call, an internal pointer points to the 1st byte.
|
||||
Now use daveGetU8(dc) to get the value of the first byte as an unsigned value. The internal buffer pointer
|
||||
is incremented by 1, now pointing to the copy of DBD1. Use daveGetS32(dc) to get the value of the
|
||||
of the next 4 bytes as a signed value. The internal pointer is incremented by 4, now pointing to
|
||||
the copy of DBD5. Use daveGetFloat(dc) to get the value of the next 4 bytes as a single precision
|
||||
float.<br>
|
||||
2. From the internal buffer, specifying a position. Use daveGetU8at(dc,0) to get the value of the
|
||||
first byte as an unsigned value. Next use daveGetS32at(dc,1) to get the value of the 4 bytes
|
||||
starting at 1 as a signed value. Finally, use daveGetFloatat(dc,5) to get the value of the 4 bytes
|
||||
starting at 5 as a single precision float. You may perform these operation in any order and also
|
||||
repeat them.<br>
|
||||
3. From a user buffer. Use daveGetU8from(buffer) to get the value of the first byte as an
|
||||
unsigned value. Use daveGetS32from(buffer+1) to get the value of the 4 bytes at buffer+1, i.e.
|
||||
DBD 1, as a signed value. Use daveGetFloatat(buffer+5) to get the value of the 4 bytes starting
|
||||
at buffer+5 as a single precision float, i.e. DBD5.<br>
|
||||
The conversion functions are named after the bit length and signedness they assume:
|
||||
<table>
|
||||
<tr><th>int buffer</th><th>int buffer+pos</th><th>buffer pointer</th><th>size</th><th>signed</th><th>C-return type</th><th>Pascal ret type</th></tr>
|
||||
<tr><td>daveGetU8</td><td>daveGetU8at</td><td>daveGetU8from</td><td>8 bit=1 byte</td><td>no</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetS8</td><td>daveGetS8at</td><td>daveGetS8from</td><td>8 bit=1 byte</td><td>yes</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetU16</td><td>daveGetU16at</td><td>daveGetU16from</td><td>16 bit=2 byte</td><td>no</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetS16</td><td>daveGetS16at</td><td>daveGetS16from</td><td>16 bit=2 byte</td><td>yes</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetU32</td><td>daveGetU32at</td><td>daveGetU32from</td><td>32 bit=4 byte</td><td>no</td><td>unsigned int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetS32</td><td>daveGetS32at</td><td>daveGetS32from</td><td>32 bit=4 byte</td><td>yes</td><td>int</td><td>longint</td></tr>
|
||||
<tr><td>daveGetFloat</td><td>daveGetFloatat</td><td>daveGetFloatfrom</td><td>32 bit=4 byte</td><td>yes</td><td>float</td><td>single</td></tr>
|
||||
</table>
|
||||
|
||||
There had been an older set of those functions named after data types, e.g.
|
||||
daveGetDWORD(). Those functions should not be used any more, as there names might be
|
||||
misunderstandable between PLC and C or other programming languages. They are still supported
|
||||
for compatibility with older versions. These functions had been inlined in earlier versions
|
||||
but are now not inlined by default, because other languages than C cannot make use of inline
|
||||
definitions in a C header file.
|
||||
<h4>Notes:</h4>
|
||||
Most commercial libraries handle the conversion issue differently: They provide functions to read one or a set of words, one or a set of long words, one or a set of reals. On the first glance, this might seem more convenient and it <b>is</b> as long as it can be applied to PLC memory areas containing only elements of the same type and size. But when you have to deal with data of mixed type and size, you would have to use another call to daveReadBytes() each time the type or size differs from the former. And each call contributes the overhead of the protocol and the response time of the PLC. Other libraries provide a way to read multiple items with a single call. So does <b>Libnodave</b>. You could also use it to retrieve data located on different boundaries. But this is limited to 20 items by the PLC. And it introduces some overhead as an address has to be transmitted for each item in the request. Use read multiple items to access data from different DBs or other memory areas when the combined results will fit in a single response.
|
||||
<table>
|
||||
<tr><th>When you want to read</td><th>do</th><th>remark</th></tr>
|
||||
<tr><td>DB20.DBD0..DBD20</td><td>read 24 bytes starting at DBB0</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD8 and DBD20</td><td>read 24 bytes starting at DBB0</td><td>just do not evaluate bytes 11 to 19 of result.</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD8 and DBD120</td><td>either read 124 bytes starting at DBB0</td><td>just do not evaluate bytes 11 to 119 of result.</td></tr>
|
||||
<tr><td></td><td>or use multiple read on: item1:DB20.DBD0..DBD8, item2:DB20.DBD120 </td><td>you have to deal with the result set.</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD8 and DB21.DBD120</td><td>use multiple read on: item1:DB20.DBD0..DBD8, item2:DB21.DBD120 </td><td>this is the only way to read from different DBs with a single request/reponse.</td></tr>
|
||||
<tr><td>DB20.DBD0..DBD118 and DB21.DBD4..DBD80</td><td>use two calls to daveReadBytes</td><td>this is the only way if the two combined results will not fit into a single PDU.</td></tr>
|
||||
<table>
|
||||
|
||||
32
doc/writemultiple.html
Normal file
32
doc/writemultiple.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<H1>Write multiple items</H1>
|
||||
The purpose of this mechanism ist to write multiple blocks of bytes from different start addresses and/or memory
|
||||
areas with a single request to the PLC.
|
||||
<H2>Basics:</H2>
|
||||
First, you have to prepare an "empty" write request, i.e. one that doesn't contain the address of an
|
||||
item. You need a variable of type PDU to store the request. To this request, you add the desired
|
||||
items using the same parameters you would specify to <a href=daveWriteBytes.html> daveWriteBytes</a>.
|
||||
You may add up to 20 different items (limit introduced by Siemens PLCs) provided that the result
|
||||
data fits into a single response PDU. When you have added all desired items, call
|
||||
daveExecWriteRequest which performs the actual data exchange with the PLC. Example:
|
||||
<pre>
|
||||
PDU p;
|
||||
daveResultSet rs;
|
||||
davePrepareWriteRequest(dc, &p);
|
||||
daveAddVarToWriteRequest(&p,daveInputs,0,0,1,buffer);
|
||||
daveAddVarToWriteRequest(&p,daveFlags,0,0,4,buffer);
|
||||
daveAddVarToWriteRequest(&p,daveDB,6,20,2,buffer);
|
||||
daveAddVarToWriteRequest(&p,daveFlags,0,12,2,buffer);
|
||||
daveAddBitVarToWriteRequest(&p,daveFlags,0,12,1,buffer);
|
||||
res=daveExecWriteRequest(dc, &p, &rs);
|
||||
</pre>
|
||||
Now the daveResultSet should contain a result for each item. Each result contains error information only. Different from daveExecReadRequest, the other member fields are 0.
|
||||
You can use these results accessing the structure daveResult directly.
|
||||
<pre>
|
||||
printf("*** Error: %s\n",daveStrerror(rs.results[2].error));
|
||||
</pre>
|
||||
If you do not need the results any more, call:
|
||||
<pre>
|
||||
daveFreeResults(&rs);
|
||||
</pre>
|
||||
This will free the memory occupied by the single results (but not by the resultSet itself),
|
||||
leaving you with an empty reultSet that can be reused in the next multi item read.
|
||||
172
faq.txt
Normal file
172
faq.txt
Normal file
@@ -0,0 +1,172 @@
|
||||
Questions I have been asked and answers:
|
||||
|
||||
Q: My VB,.NET or Delphi application doesn't work. I suppose libnodave doesn't work with my
|
||||
hardware or doesn't work at all. Can you help me?
|
||||
A: You can most easily find out whether Libnodave works with your hardware, PLC, adapter
|
||||
etc: try the precompiled test programs. If they don't work (trying different options when
|
||||
suggested), it's clearly libnodave's fault.
|
||||
If they work, it's your application (or there is a little chance, the problem is in the
|
||||
interface to the language you use).
|
||||
|
||||
Q: Can you help me?
|
||||
A: Before asking me, try out the test programs as described above. When they don't work for
|
||||
you, send me the output with debug option, e.g. do:
|
||||
testMPI -d COM1 >debugout.txt
|
||||
If they work, but your application doesn't, do:
|
||||
Insert "daveSetDebug(daveDebugAll)" before calling anything else from libnodave.
|
||||
Then do:
|
||||
yourappliation >debugout.txt
|
||||
For those people who grew up with mice and don't know the command line:
|
||||
This works even with MS-Excel. Create a spreadsheet, import the VBA module,
|
||||
- uncomment the "call daveSetDebug(daveDebugAll)" at the begin of sub initialize,
|
||||
- save the sheet.
|
||||
- then, from commandline (dos box, cmd) do:
|
||||
excel testsheet >debugout.txt
|
||||
All debug output (otherwise invisible) goes into debugout.txt.
|
||||
When time falls short, I shall discard mails not containig debug output!
|
||||
|
||||
Q: What mail format do you prefer?
|
||||
A: Ok, nobody asked that, but I DO prefer PLAIN TEXT.
|
||||
|
||||
Q: I want to read out whether my PLC is in RUN or STOP mode. Is there a function for that?
|
||||
A: No, not a specialized one. For S7-300/400, use daveReadSZL to read the diagnostic lists.
|
||||
This is what Step7 does. You will find information about IDs and indices in Siemens
|
||||
documentation. The state of all the CPU LEDs is in ID 25 (19hex) index 0.
|
||||
With S7-200, the information is somewhere in the system data.
|
||||
|
||||
Q: I trying to trace libnodave with a debugger. I need help?
|
||||
A: There is no reason to use a debugger on libnodave unless you suspect one of the
|
||||
following things:
|
||||
- memory leaks
|
||||
- range overflows, on numbers or array indices
|
||||
- problems with passing parameters to library functions
|
||||
In the latter case, better recompile libnodave after uncommenting #define DEBUG_CALLS in
|
||||
nodave.c.
|
||||
To find problems with PLCs and adapters, the FAR better way is to use
|
||||
setDaveDebug(daveDebugAll). This will show you what is sent and received from PLC/adapter
|
||||
and it will show you the relevant information instead of extracting it from memory
|
||||
contents or processor registers. Thus, data exchange with the PLC is still carried out with
|
||||
normal timing. With a debugger, the code might send one part of a message and then pause
|
||||
longer than PLC side timeouts.
|
||||
|
||||
Q: Can you give documentation about S7 communication or MPI protocol?
|
||||
A: No, I can't. What I know about it is from reverse engineering. This means sniffing lots of
|
||||
packets, trying to make sense of them and trying to generate them with my own code.
|
||||
If things are named so or so in libnodave this reflects my current hypothesis. I could
|
||||
try to write documentation, but that would allways be a step behind the code: The code
|
||||
is what can be proven against existing hardware, i.e. reaity. The docs cannot. And I think
|
||||
the code is fairly well documented...
|
||||
|
||||
Q: So why do you have these complicated structures?
|
||||
A: What people might have found complicated are probably the pointers to protocol dependent
|
||||
functions. In fact, they make the library more simple in two ways:
|
||||
- First, they separate packet forming from transport. If someone finds out how to do some
|
||||
function that can be done with a Simatic S7, it is sufficient to implement the packet
|
||||
forming part and it will most likely work with any transport protocol. Vice versa, if there
|
||||
would be a new transport mechanism, probaly all functions will work with it as soon as the
|
||||
transport functions are implemented. Version 0.8 clearly shows that by implementing a
|
||||
transport vie s7online.dll.
|
||||
- Commercial libraries I looked at usually have separate sets of functions for the 200
|
||||
and the 300/400 family. Libnodave hasn't, so you have less to learn about the API while your
|
||||
code can do more without any modification.
|
||||
|
||||
Q: Why do you export these structures if you say they are meaningless for applications?
|
||||
A: They are not completely meaningless. There are also a lot of "intermediate step functions"
|
||||
that are exported from the .dll or.so which are normally of no use to end users.
|
||||
- All this is there - in the spirit of open source - for those who want to do their
|
||||
own experiments. It may give you possibilities I did not think of.
|
||||
- At least once, I could help a user implementing a new function (daveForce200). He only
|
||||
had to add about 20 lines to his application which in turn called intermediate steps
|
||||
of packet forming and analysis, like _daveAddData.
|
||||
|
||||
Q: Why aren't there functions like readOutputs, readInputs, readData ?
|
||||
A: Other libraries usually have separate functions to read from inputs, outputs, flags,
|
||||
data blocks and so on. Libnodave hasn't. Again, you have to learn less about the API.
|
||||
|
||||
Q: Why aren't there functions like readBytes, readIntegers, readDWords, readFloat ?
|
||||
A: Other libraries often have separate functions to read integers, dwords or floats.
|
||||
Libnodave hasn't. The reason is: If you have a DB (or memory area) containg mixed data
|
||||
types, with those function you can only read parts of such a block. Or you use readBytes
|
||||
to read the memory as raw bytes and you are left alone wit the conversion.
|
||||
Libnodave generally reads an entire block of data as bytes and then provides you
|
||||
with conversion functions to convert it to PLC data types and byte order.
|
||||
|
||||
Q: I try to compile my source code which includes nodave.h. Why do I get:
|
||||
"#error Fill in what you need for your OS or API" ?
|
||||
A: Libnodave has to use different functions to read byte data from serial ports or TCP/IP streams
|
||||
depending on the operating system. You have to specify which OS you compile for.
|
||||
Define BCCWIN for Windows and LINUX for Linux or other Unix style operating systems. I do
|
||||
that using -DBCCWIN or -DLINUX when I call the compilers out of a Makefile. If you use an IDE
|
||||
(integrated development environment), refer to the IDE's documentation to learn where to do
|
||||
this. If you can't find out, you can help yourself putting the #define into your code (which
|
||||
means your code will not be portable to other OS without modification). example:
|
||||
|
||||
...
|
||||
#define BCCWIN // if you work on windows
|
||||
#include nodave.h // or nodavesimple.h, but NEVER both
|
||||
#include setport.h // if your code works with serial connections
|
||||
#include openSocket.h // if your code works with TCP/IP
|
||||
...
|
||||
Q: I try to compile libnodave from source code. There are problems.
|
||||
A: - You do not need to compile libnodave yourself. You won't do it with other DLLs (windows)
|
||||
or .so (Linux shared libraries). Normally, you will link such libraries dynamically with
|
||||
your code.
|
||||
- Nevertheless, you have the sources and you may chose to recompile it or recompile only the
|
||||
parts you need, etcetera.
|
||||
- You should know that S7 uses Motorola (big endian, high byte first) byte order (endianness)
|
||||
while Intel processors use Intel (little endian, low byte first). On Intel and similar
|
||||
machines, libnodave has to convert multibyte values. This is done in daveGetS2(), daveGetU2(),
|
||||
daveGetFloat() and friends. The conversion code is only compiled in if you #define
|
||||
DAVE_LITTLE_ENDIAN. Otherwise, big endian is assumed.
|
||||
- Be aware that I do compile releases of libnodave using gcc (for Linux) and MSVC++
|
||||
(for windows). I use the script buildall to build Linux and Windows release versions and test
|
||||
programs on a Linux box. Buildall uses Linux make with MAKEFILE.VC.WINE to invoke the MSVC++
|
||||
compiler for windows versions. There is also a MAKEFILE.VC which should work on a windows
|
||||
system using nmake, but it may be out of date :-(. If in doubt about compiler options or
|
||||
source files involved, refer to MAKEFILE.VC.WINE!
|
||||
|
||||
Q: I want to compile libnodave for another OS. What adaptions shall I have to make?
|
||||
A: - I suppose your OS is 32 bit and your compiler treats int as 32 bit. If not, you are in
|
||||
trouble!
|
||||
- You need to provide functional replacements for setport.c or setportw.c and openSocket.c or
|
||||
openSocketw.c
|
||||
- nodave.h: You need to define a record _daveOSserialType containing members:
|
||||
rfd: a data type that can refer to a serial port or a TCP socket for read access
|
||||
wfd: a data type that can refer to a serial port or a TCP socket for write access
|
||||
- nodave.c: You need to code functions stdread() and stdwrite() to read and write a number of
|
||||
bytes from/to a serial port to/from a buffer.
|
||||
|
||||
Q: Is there a function to read PLC Data structure of a data block? The variables
|
||||
and their data type ?
|
||||
A: No. The structure information is only available to Step7 BEFORE compilation. It is NOT stored
|
||||
in the PLC itself. Same situation if you open a new project and load the code from PLC into
|
||||
programmer: Your DBs will be nothing more than arrays of bytes.
|
||||
|
||||
Q: I have problems writing inputs. Can you help me?
|
||||
A: Well, there are 2 types of inputs: 1. Peripheral adresses. This is what you read with daveP
|
||||
or, in a PLC program, with L PIW <address>. Accesses to these addresses are real hardware
|
||||
read or write accesses and there is no way to write to input hardware.
|
||||
2. Input/Output image memory. This is how programmers normally access Siemens I/O like in:
|
||||
L IW <address>
|
||||
or
|
||||
A I 2.5
|
||||
Accesses to these addresses do NO access the hardware but a special memory area. The
|
||||
inputs are copied to this memory in each cycle before the application program is executed.
|
||||
If you write to this memory area using daveInputs, the memory will be overwritten before next
|
||||
cycle. Whether your PLC program or your application of Libnodave will "see" the values written
|
||||
to this memory is a matter of time race.
|
||||
|
||||
Q: Is it possible to write a number of bits (up to 3) simultaneously to the PLC?
|
||||
I want to avoid using "read-modify-write" techniques and make the write as "atomic"
|
||||
as possible.
|
||||
A: daveWriteBits() does provide an "atomic" write function, but only for a single bit.
|
||||
The length parameter to daveWriteBits() has to be one, other values produce errors with
|
||||
CPUs that I know of. So why is this parameter there? It corresponds to a field in the message
|
||||
which contains the number of bits to read or write.
|
||||
|
||||
Q: Can this (an atomic read to 3 bits) be done using daveWriteBits() or do I have to use multiple
|
||||
write "items" within the same PDU?
|
||||
A: It CANNOT be done with daveWriteBits() with the CPUs I know. Whether writing with a PDU containing
|
||||
multiple items is "atomic" or not I don't know. If you can modify the PLC program, I think the best
|
||||
solution would be locating the 3 bits into a byte the rest of which remains unused.
|
||||
|
||||
49
filelist
Normal file
49
filelist
Normal file
@@ -0,0 +1,49 @@
|
||||
accepter.c include file for servers
|
||||
benchmark.c include file for benchmarks
|
||||
ibhtest7.c Partly simulates an IBH-NetLink
|
||||
isotest4.c Partly simulates an Ethernet CP x43
|
||||
libnodave.so Precompiled dynamic library
|
||||
libnodave.DEF Defines names to export for the Microsoft linker
|
||||
loadPLC
|
||||
log.h
|
||||
Makefile Makefile for LINUX/UNIX
|
||||
MAKEFILE.MAK Makefile for WIN32/BCC
|
||||
nodave.c Main library source code file
|
||||
nodave.h Library header file
|
||||
nodavesimple.h Simplified Library header file. This file is not intended to be used as the
|
||||
header file for your application. It is there to give a hind to people who
|
||||
want to use libnodave from applications in VB or dot.net what is the minimum
|
||||
they must make known to these languages for simple applications. I use it in
|
||||
test applications only to verify that is sufficient indeed.
|
||||
openSocket.c Opens a TCP/IP connection. Library source code file
|
||||
openSocket.h Library header file (UNIX only)
|
||||
openSocketw.c Library header file (Win32 only)
|
||||
pascal Pascal glue unit and example programs
|
||||
README
|
||||
Readme.win
|
||||
readoutISO_TCP Readout program blocks from PLC, ISO over TCP protocol
|
||||
readoutMPI Readout program blocks from PLC, MPI protocol, serial interface
|
||||
readoutMPIIBH Readout program blocks from PLC, MPI protocol, ethernet with IBH-NetLink
|
||||
readoutPPI Readout program blocks from PLC, PPI protocol, serial interface
|
||||
runStopISO_TCP Make PLC run or stop, ISO over TCP protocol
|
||||
runStopMPI Make PLC run or stop, ISO over TCP protocol
|
||||
runStopPPI Make PLC run or stop, ISO over TCP protocol
|
||||
sampIBH.c include file for NetLink simulation
|
||||
setport.c Opens a serial interface. Library source code file
|
||||
setport.h Library header file (UNIX only)
|
||||
setportw.c Library header file (Win32 only)
|
||||
testIBH General test program for MPI over IBH/MHJ-NetLink.
|
||||
testISO_TCP General test program.
|
||||
testISO_TCPload Store program blocks into PLC, ISO over TCP protocol
|
||||
testMPI General test program.
|
||||
testMPI2 Tests multiple MPI connections to a single PLC.
|
||||
testMPIload Store program blocks into PLC, MPI protocol
|
||||
testPPI General test program.
|
||||
testPPI_IBH General test program for PPI over IBH/MHJ-NetLink.
|
||||
testPPIload Store program blocks into PLC, PPI protocol
|
||||
testPPI_IBHload Store program blocks into PLC, PPI over IBH/MHJ-NetLink.
|
||||
win DLL, .lib file and precompiled test programs for Win32
|
||||
winmake.bat Batch file to compile under Win32
|
||||
MAKEFILE.VC.WINE Makefile to build libnodave.dll and test programs with MSVC++ under wine
|
||||
MAKEFILE.WINE Makefile to build libnodave.dll and test programs with BorlandC under wine
|
||||
|
||||
89
ibhsamples6.c
Normal file
89
ibhsamples6.c
Normal file
@@ -0,0 +1,89 @@
|
||||
us cha0[]={
|
||||
0x00,0xff,0x03,0x00,0x00,0x00,0x04,0x00, 0x03,0x07,0x02,
|
||||
};
|
||||
|
||||
uc res0[]={
|
||||
0xff,0x00,0xfe,0x00,0x04,0x00,0x00,0x00, 0x00,0x07,0x02,0x03,0x1f,0x00,0x02,0x00,
|
||||
0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x3e, 0x9f,0x01,0x01,0x00,0x01,0x00,0x3c,0x00,
|
||||
0x90,0x01,0x10,0x27,0x00,0x00,0x14,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x48, 0x69,0x6c,0x73,0x63,0x68,0x65,0x72,0x20,
|
||||
0x47,0x6d,0x62,0x48,0x20,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x01,0xff,
|
||||
};
|
||||
|
||||
us cha1[]={ /* used in C */
|
||||
0x07,0xff,0x08,0x01,0x00,0x00,0x96,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x01,
|
||||
};
|
||||
|
||||
#define isReachable 0x30
|
||||
#define isNotReachable 0xff
|
||||
|
||||
uc res1[]={ /* used in C */
|
||||
0xff,0x07,0x87,0x01,0x96,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x7f,0x0a,0x02,
|
||||
0x30,0xff,0x30,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
};
|
||||
|
||||
us cha2[]={/* used in C */
|
||||
0x00,0x10,0x01,0x00,0x00,0x00,0x01,0x00, 0x0f,
|
||||
};
|
||||
|
||||
uc res2[]={
|
||||
0x10,0x00,
|
||||
0x20,
|
||||
0x00,
|
||||
0x01,0x00,0x00,0x00,
|
||||
0x01,0x06,0x20,0x03,0x17,0x00,0x43,0x00,
|
||||
0x00,0x00,0x22,0x21,0x00,0x00,0x00,0x00, 0x49,0x42,0x48,0x53,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
us cha3[]={/* used in C */
|
||||
0x07,0xff,0x06,0x01,0x00,0x00,0x97,0x00, 0x114,0x1ff,0xf0,0xf0,0xf0,0xf0,
|
||||
};
|
||||
|
||||
uc res3[]={
|
||||
0xff,0x07,0x02,0x01,0x97,0x00,0x00,0x00, 0x14,0x00,
|
||||
};
|
||||
|
||||
us cha8[]={ /* used in C */
|
||||
0x07,0xff,0x07,0x03,0x00,0x00,0x82,0x00, 0x114,0x114,0x103,0x00,0x02,0x05,0x01,
|
||||
};
|
||||
|
||||
uc res7[]={
|
||||
0xff,0x07,0x09,0x00,0x00,0x00,0xc2,0x02, 0x14,0x14,0x03,0x00,0x00,0x22,0x02,0x05,
|
||||
0x01,
|
||||
};
|
||||
|
||||
|
||||
us cha11[]={ /* used in C */
|
||||
0x07,0xff,0x19,0x04,0x00,0x00,0x82,0x00, 0x114,0x114,0x103,0x00,0x14,0xf1,0x00,0x32,
|
||||
0x01,0x00,0x00,0x101,0x00,0x00,0x08,0x00, 0x00,0xf0,0x00,0x00,0x101,0x00,0x102,0x00,
|
||||
0xf0,
|
||||
};
|
||||
|
||||
uc res10[]={
|
||||
0xff,0x07,0x1d,0x00,0x00,0x00,0xc2,0x02, 0x14,0x14,0x03,0x00,0x00,0x22,0x16,0xf1,
|
||||
0x00,0x32,0x03,0x00,0x00,0x02,0x00,0x00, 0x08,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,
|
||||
0x01,0x00,0x01,0x00,0xf0,
|
||||
};
|
||||
|
||||
|
||||
|
||||
928
ibhsim5.c
Normal file
928
ibhsim5.c
Normal file
@@ -0,0 +1,928 @@
|
||||
/*
|
||||
Part of Libnodave, a free communication libray for Siemens S7 300/400.
|
||||
This program simulates the IBHLink MPI-Ethernet-Adapter from IBH-Softec.
|
||||
www.ibh-softec.de
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2002.
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Visual; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "log2.h"
|
||||
|
||||
#define ThisModule "IBHtest : "
|
||||
#define uc unsigned char
|
||||
|
||||
#include "nodave.h"
|
||||
#include "ibhsamples6.c"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "accepter.c"
|
||||
|
||||
#include "simProperties.c"
|
||||
|
||||
#define bSize 1256
|
||||
#define us unsigned short
|
||||
|
||||
#define debug 12
|
||||
|
||||
extern int daveDebug;
|
||||
#define daveDebugAnalyze 0x40000
|
||||
|
||||
void analyze(daveConnection * dc);
|
||||
/*
|
||||
many bytes. hopefully enough to serve any read request.
|
||||
*/
|
||||
uc dummyRes[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,12,13,14,1,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,12,13,14,1,
|
||||
5,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,5,16,1,2,3,4,5,6,7,8,9,10,
|
||||
11,12,13,14,15,16,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,12,13,14,1,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,
|
||||
12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,12,13,14,1,
|
||||
5,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,5,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,};
|
||||
/*
|
||||
a read callback function
|
||||
*/
|
||||
uc * dummyRead (int area, int DBnumber, int start, int len, int * res) {
|
||||
printf("User callback should deliver pointer to %d bytes from %s %d beginning at %d.\n",
|
||||
len, daveAreaName(area),DBnumber,start);
|
||||
*res=0;
|
||||
|
||||
return dummyRes;
|
||||
};
|
||||
|
||||
void myWrite (int area, int DBnumber, int start, int len, int * res, uc*bytes) {
|
||||
printf("User callback1 should write %d bytes to %s %d beginning at %d.\n",
|
||||
len, daveAreaName(area),DBnumber,start);
|
||||
printf("User callback 1.\n");
|
||||
*res=0;
|
||||
start=start/8;
|
||||
memcpy(dummyRes+start,bytes,len);
|
||||
printf("User callback done.\n");
|
||||
fflush(stdout);
|
||||
};
|
||||
|
||||
int handleTime(PDU *p1, PDU *p2){
|
||||
if (p1->param[6]==1) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x87,0x01,0x01, 0x00,0x00,0,0,};
|
||||
printf("Get time from CPU.\n");
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, CpuTimeStamp, sizeof(CpuTimeStamp));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (p1->param[6]==2) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x87,0x02,0x01, 0x00,0x00,0,0,};
|
||||
printf("Set CPU time.\n");
|
||||
memcpy(CpuTimeStamp, p1->data+4,sizeof(CpuTimeStamp));
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, CpuTimeStamp, sizeof(CpuTimeStamp));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else {
|
||||
printf("Cannot handle this\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int handleBlocks(PDU *p1, PDU *p2){
|
||||
printf("Block handling Commands(%d) ???? ????\n",p1->param[6]);
|
||||
if (p1->param[6]==1) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x83,0x01,0x00, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, blockList, sizeof(blockList));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (p1->param[6]==2) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x83,0x02,0x00, 0x00,0x00,0x00,0x00,};
|
||||
uc da[]={0x0a,0x0,0x0,0x0,};
|
||||
uc SDBs[]={0x00,0x01,0x22,0x11,0x00,0x02,0x22,0x11};
|
||||
printf("List Blocks of type %s\n",daveBlockName(p1->data[5]));
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
|
||||
if(p1->data[5]==0x42) {
|
||||
_daveAddUserData(p2, SDBs, sizeof(SDBs));
|
||||
} else {
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
}
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (p1->param[6]==3) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x83,0x03,0x00, 0x00,0x00,0xd2,0x09,};
|
||||
uc da[]={0x0a,0x0,0x0,0x0,};
|
||||
printf("get Block info/header %s\n",daveBlockName(p1->data[5]));
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else {
|
||||
printf("Cannot handle this\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int handleReadProgram(PDU *p1, PDU *p2){
|
||||
uc pa[]={
|
||||
0x1D,0x00,0x01,0x00,0x00,0x00,0x00,0x07,0x07,0x30,0x30,0x30,0x30,0x30,0x37,0x32,
|
||||
};
|
||||
printf("Program block readout.\n");
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
// if(daveDebug & daveDebugPDU)
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct __ls {
|
||||
uc * content;
|
||||
int gotlen;
|
||||
int totlen;
|
||||
int number;
|
||||
int PDUnumber;
|
||||
int typ;
|
||||
} loadStruct;
|
||||
|
||||
//#define ploaderror
|
||||
int handleLoadProgram(daveConnection *dc,PDU *p1, PDU *p2,int PDUnumber, uc*resp, loadStruct * ls){
|
||||
int n;
|
||||
uc pa[]={
|
||||
0x1A
|
||||
};
|
||||
uc pa2[]={
|
||||
0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x5F,0x30,0x38,0x30,0x30,0x30,0x30,0x31,0x50,
|
||||
};
|
||||
#ifndef ploaderror
|
||||
printf("Program block load.\n");
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
ls->typ=p1->param[11];
|
||||
printf("block type %s. ",daveBlockName(ls->typ));
|
||||
ls->number=atol((char*)p1->param+12);
|
||||
ls->PDUnumber=1;
|
||||
printf("number: %d\n",ls->number);
|
||||
p1->param[26]=0;
|
||||
ls->totlen=atol((char*)p1->param+20);
|
||||
ls->gotlen=0;
|
||||
printf("total size: %d\n",ls->totlen);
|
||||
ls->content=(uc*)malloc(ls->totlen);
|
||||
resp[22]=PDUnumber % 256; // test!
|
||||
resp[21]=PDUnumber / 256; // test!
|
||||
_daveDumpPDU(p2);
|
||||
write(dc->iface->fd.rfd,resp,resp[2]+8);
|
||||
_daveInitPDUheader(p2,1);
|
||||
pa2[11]=ls->typ;
|
||||
n=ls->number;
|
||||
pa2[16]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa2[15]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa2[14]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa2[13]=0x30+(n %10);
|
||||
_daveAddParam(p2, pa2, sizeof(pa2));
|
||||
#else
|
||||
_daveInitPDUheader(p2,2);
|
||||
p2->header[10]=0xD2;
|
||||
p2->header[11]=0x09;
|
||||
#endif
|
||||
// _daveAddParam(p2, pa, sizeof(pa));
|
||||
// if(daveDebug & daveDebugPDU)
|
||||
/*
|
||||
resp[22]=PDUnumber % 256; // test!
|
||||
resp[21]=PDUnumber / 256; // test!
|
||||
*/
|
||||
_daveDumpPDU(p2);
|
||||
write(dc->iface->fd.rfd,resp,resp[2]+8);
|
||||
/*
|
||||
dc->AnswLen=_daveReadIBHPacket(dc->iface, dc->msgIn);
|
||||
analyze(dc);
|
||||
// _daveDump("I sent:",resp,resp[2]+8);
|
||||
LOG1(ThisModule);
|
||||
_daveDump("epacket 1", dc->msgIn, dc->AnswLen);
|
||||
dc->AnswLen=_daveReadIBHPacket(dc->iface, dc->msgIn);
|
||||
analyze(dc);
|
||||
// _daveDump("I sent:",resp,resp[2]+8);
|
||||
LOG1(ThisModule);
|
||||
_daveDump("epacket 2", dc->msgIn, dc->AnswLen);
|
||||
dc->AnswLen=_daveReadIBHPacket(dc->iface, dc->msgIn);
|
||||
analyze(dc);
|
||||
// _daveDump("I sent:",resp,resp[2]+8);
|
||||
LOG1(ThisModule);
|
||||
_daveDump("epacket 3", dc->msgIn, dc->AnswLen);
|
||||
dc->AnswLen=_daveReadIBHPacket(dc->iface, dc->msgIn);
|
||||
analyze(dc);
|
||||
// _daveDump("I sent:",resp,resp[2]+8);
|
||||
LOG1(ThisModule);
|
||||
_daveDump("epacket 4", dc->msgIn, dc->AnswLen);
|
||||
*/
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int handleContLoadProgram(daveConnection *dc,PDU *p1, PDU *p2,int PDUnumber, uc*resp, loadStruct * ls){
|
||||
int n;
|
||||
uc pa2[]={
|
||||
0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x5F,0x30,0x38,0x30,0x30,0x30,0x30,0x34,0x50,
|
||||
};
|
||||
uc pa3[]={
|
||||
// 0x1C,0x00,0x84,0x04,0x00,0x00,0x00,0x00,0x09,0x5F,0x30,0x38,0x30,0x30,0x30,0x30,0x34,0x50,
|
||||
0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x5F,0x30,0x38,0x30,0x30,0x30,0x30,0x34,0x50,
|
||||
};
|
||||
printf("total size: %d have %d\n",ls->totlen,ls->gotlen);
|
||||
ls->gotlen +=p1->dlen-4;
|
||||
printf("total size: %d have %d\n",ls->totlen,ls->gotlen);
|
||||
|
||||
n=ls->number;
|
||||
pa2[16]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa2[15]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa2[14]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa2[13]=0x30+(n %10);
|
||||
pa2[11]=ls->typ;
|
||||
|
||||
n=ls->number;
|
||||
pa3[16]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa3[15]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa3[14]=0x30+(n %10);
|
||||
n/=10;
|
||||
pa3[13]=0x30+(n %10);
|
||||
pa3[11]=ls->typ;
|
||||
|
||||
if (p1->param[1]==1) {
|
||||
_daveAddParam(p2, pa2, sizeof(pa2));
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
_daveAddParam(p2, pa3, sizeof(pa3));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int handleEndLoadProgram(daveConnection *dc,PDU *p1, PDU *p2,int PDUnumber, uc*resp, loadStruct * ls){
|
||||
uc pa[]={
|
||||
0x1C
|
||||
};
|
||||
printf("Program block readout.\n");
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
// if(daveDebug & daveDebugPDU)
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int handleContinueReadProgram(PDU *p1, PDU *p2){
|
||||
uc pa[]={
|
||||
0x1E,0x00
|
||||
};
|
||||
uc da[]={
|
||||
0x00,0x48,0x00,0xFB, 0x70,0x70,0x00,0x0A, 0x11,0x0B,0x00,0x01, 0x00,0x00,0x00,0x48,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x0E,0x45,0x00,0x00, 0x00,0x00,0x0E,0x45,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x24, 0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x01,0x7F,0xFF, 0x00,0x00,0x22,0x00, 0x00,0x01,0x00,0xC0,
|
||||
};
|
||||
|
||||
printf("Program block readout.\n");
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
// if(daveDebug & daveDebugPDU)
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int handleEndReadProgram(PDU *p1, PDU *p2){
|
||||
uc pa[]={
|
||||
0x1F
|
||||
};
|
||||
printf("Program block readout.\n");
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
// if(daveDebug & daveDebugPDU)
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int handleSZL(int number, int index, PDU *p2){
|
||||
if ((number==292) && (index==0)) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_292_0, sizeof(SZL_292_0));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==274) && (index==512)) { /* read order code (MLFB) */
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_274_512, sizeof(SZL_274_512));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==0) && (index==0)) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_0_0, sizeof(SZL_0_0));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==25) && (index==0)) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_25_0, sizeof(SZL_25_0));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==273) && (index==1)) { /* read order code (MLFB) */
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_273_1, sizeof(SZL_273_1));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==305) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
switch (index) {
|
||||
case 1: _daveAddUserData(p2, SZL_305_1, sizeof(SZL_305_1)); break;
|
||||
case 2: _daveAddUserData(p2, SZL_305_2, sizeof(SZL_305_1)); break;
|
||||
case 3: _daveAddUserData(p2, SZL_305_3, sizeof(SZL_305_1)); break;
|
||||
case 4: _daveAddUserData(p2, SZL_305_4, sizeof(SZL_305_1)); break;
|
||||
case 5: _daveAddUserData(p2, SZL_305_5, sizeof(SZL_305_1)); break;
|
||||
case 6: _daveAddUserData(p2, SZL_305_6, sizeof(SZL_305_1)); break;
|
||||
case 7: _daveAddUserData(p2, SZL_305_7, sizeof(SZL_305_1)); break;
|
||||
case 8: _daveAddUserData(p2, SZL_305_8, sizeof(SZL_305_1)); break;
|
||||
case 9: _daveAddUserData(p2, SZL_305_9, sizeof(SZL_305_1)); break;
|
||||
}
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==306) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
switch (index) {
|
||||
case 1: _daveAddUserData(p2, SZL_306_1, sizeof(SZL_306_1)); break;
|
||||
case 2: _daveAddUserData(p2, SZL_306_2, sizeof(SZL_306_2)); break;
|
||||
case 4: _daveAddUserData(p2, SZL_306_4, sizeof(SZL_306_4)); break;
|
||||
}
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==0xD91) && (index==0)) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_3473_0, sizeof(SZL_3473_0));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==1060) && (index==0)) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
if (runStop == runModeRun)
|
||||
_daveAddUserData(p2, SZL_1060_0, sizeof(SZL_1060_0));
|
||||
else if (runStop == runModeStop)
|
||||
_daveAddUserData(p2, SZL_1060_0S, sizeof(SZL_1060_0S));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if ((number==1316) && (index==20480)) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddUserData(p2, SZL_1316_20480, sizeof(SZL_1316_20480));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0xD4,0x01,};
|
||||
uc da[]={0x0a,0x0,0x0,0x0,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
if(daveDebug & daveDebugPDU)_daveDumpPDU(p2);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int handleSystemMessage(PDU * p1,PDU * p2) {
|
||||
int number;
|
||||
int index;
|
||||
if (
|
||||
(p1->param[1]==1) &&
|
||||
(p1->param[2]==18) &&
|
||||
(p1->param[3]==4) &&
|
||||
(p1->param[4]==17) &&
|
||||
(p1->param[5]=='D')
|
||||
) {
|
||||
number=0x100*(p1->data[4])+p1->data[5];
|
||||
index=0x100*(p1->data[6])+p1->data[7];
|
||||
printf("SZL read ID: %04X index: %d\n",number,index);
|
||||
return handleSZL(number,index,p2);
|
||||
} else if (
|
||||
(p1->param[1]==1) &&
|
||||
(p1->param[2]==18) &&
|
||||
(p1->param[3]==4) &&
|
||||
(p1->param[4]==17) &&
|
||||
(p1->param[5]=='C')
|
||||
) {
|
||||
printf("Block functions\n");
|
||||
return handleBlocks(p1,p2);
|
||||
}
|
||||
else if (
|
||||
(p1->param[1]==1) &&
|
||||
(p1->param[2]==18) &&
|
||||
(p1->param[3]==4) &&
|
||||
(p1->param[4]==17) &&
|
||||
(p1->param[5]=='G')
|
||||
) {
|
||||
printf("Time System ????\n");
|
||||
return handleTime(p1,p2);
|
||||
} else if (
|
||||
(p1->param[1]==1) &&
|
||||
(p1->param[2]==18) &&
|
||||
(p1->param[3]==8) &&
|
||||
(p1->param[4]==18) &&
|
||||
(p1->param[5]=='A')
|
||||
) {
|
||||
if(p1->param[6]==16) {
|
||||
printf("Forces ???? ????\n");
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x81,0x10,0x00, 0x00,0x00,0xD0,0x02,};
|
||||
uc da[]={0,4,0,4,1,0,0,1,16,1,0,0};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if(p1->param[6]==12) {
|
||||
printf("Erase ???? ????\n");
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x81,0x12,0x00, 0x00,0x00,0x0,0x0,};
|
||||
uc da[]={0x0a,0x0,0x0,0x0,};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else {
|
||||
printf("Programmer Commands(%d) ???? ????\n",p1->param[6]);
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x81,0x10,0x00, 0x00,0x00,0xD0,0x04,};
|
||||
uc da[]={0x0a,0x0,0x0,0x0,};
|
||||
pa[6]=p1->param[6];
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, da, sizeof(da));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("Cannot handle this!\n");
|
||||
return 0;
|
||||
};
|
||||
|
||||
int handleNegociate(PDU * p1,PDU * p2) {
|
||||
uc pa[]={0xF0,0x0,0x0,0x1, 0x00,0x01,0x00,0xF0};
|
||||
davePut16At(pa, 6, simMaxPDUlength);
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
return 1;
|
||||
};
|
||||
|
||||
int handleStop(PDU * p1,PDU * p2) {
|
||||
uc pa[]={0x29};
|
||||
runStop=runModeStop;
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
return 1;
|
||||
};
|
||||
|
||||
int handleRun(PDU * p1,PDU * p2, loadStruct * ls) {
|
||||
uc pa[]={0x28};
|
||||
runStop=runModeRun;
|
||||
_daveInitPDUheader(p2,3);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
return 1;
|
||||
};
|
||||
|
||||
int gpacketNumber=0;
|
||||
|
||||
uc r5[]={
|
||||
0xff,0x07,0x13,0x00,0x00,0x00,0xc2,0x02, 0x14,0x14,0x03,0x00,0x00,0x22,0x0c,0xd0,
|
||||
0x04,0x00,0x80,0x00,0x02,0x00,0x02,0x01,0x00,0x01,0x00,
|
||||
};
|
||||
|
||||
void _daveSendIBHNetAck2(daveConnection * dc) {
|
||||
// 0xff,0x07,0x05,0x02,0x82,0x00,0x00,0x00, 0x14,0x00,0x03,0x01,0x09,
|
||||
IBHpacket * p;
|
||||
uc ack[13],c;
|
||||
us d;
|
||||
memcpy(ack, dc->msgIn, sizeof(ack));
|
||||
p= (IBHpacket*) ack;
|
||||
d=p->sFlags; p->sFlags=p->rFlags; p->rFlags=d;
|
||||
c=p->ch1; p->ch1=p->ch2; p->ch2=c; // certainly nonsense, but I cannot test it
|
||||
c=ack[9]; // at the moment, and because it DID work,
|
||||
ack[9]=ack[10];
|
||||
ack[10]=c; // I'll leave it as it is.
|
||||
p->len=sizeof(ack)-sizeof(IBHpacket);
|
||||
ack[11]=1;
|
||||
ack[12]=9;
|
||||
// LOG2("Sending net level ack for number: %d\n",p->packetNumber);
|
||||
if (daveDebug & daveDebugMPI){
|
||||
_daveDump("I send ack", ack,sizeof(ack));
|
||||
}
|
||||
_daveWriteIBH(dc->iface, ack,sizeof(ack));
|
||||
}
|
||||
|
||||
loadStruct lost;
|
||||
|
||||
void analyze(daveConnection * dc) {
|
||||
IBHpacket * p2;
|
||||
MPIheader2 * m2;
|
||||
uc resp[2000];
|
||||
int PDUnumber;
|
||||
int haveResp=0;
|
||||
PDU p1,pr;
|
||||
IBHpacket * p= (IBHpacket*) dc->msgIn;
|
||||
dc->needAckNumber=-1; // Assume no ack
|
||||
/*
|
||||
printf("Channel: %d\n",p->ch1);
|
||||
printf("Channel: %d\n",p->ch2);
|
||||
printf("Length: %d\n",p->len);
|
||||
printf("Number: %d\n",p->packetNumber);
|
||||
printf("sFlags: %04x rFlags:%04x\n",p->sFlags,p->rFlags);
|
||||
*/
|
||||
if (p->rFlags==0x82) {
|
||||
MPIheader * pm= (MPIheader*) (dc->msgIn+sizeof(IBHpacket));
|
||||
if (daveDebug & daveDebugAnalyze){
|
||||
printf("srcconn: %d\n",pm->src_conn);
|
||||
printf("dstconn: %d\n",pm->dst_conn);
|
||||
printf("MPI: %d\n",pm->MPI);
|
||||
printf("MPI len: %d\n",pm->len);
|
||||
printf("MPI func:%d\n",pm->func);
|
||||
}
|
||||
if (pm->func==0xf1) {
|
||||
if (daveDebug & daveDebugAnalyze){
|
||||
printf("0xf1:PDU transport, MPI packet number: %d\n",pm->packetNumber);
|
||||
}
|
||||
dc->needAckNumber=pm->packetNumber;
|
||||
dc->PDUstartI=sizeof(IBHpacket)+sizeof(MPIheader);
|
||||
_daveSetupReceivedPDU(dc, &p1);
|
||||
|
||||
PDUnumber=p1.header[5]+256*p1.header[4];
|
||||
|
||||
_daveDumpPDU(&p1);
|
||||
// construct response:
|
||||
pr.header=resp+sizeof(IBHpacket)+sizeof(MPIheader2);
|
||||
p2= (IBHpacket*) resp;
|
||||
p2->ch1=p->ch2;
|
||||
p2->ch2=p->ch1;
|
||||
p2->packetNumber=0;
|
||||
p2->sFlags=0;
|
||||
p2->rFlags=0x2c2;
|
||||
m2= (MPIheader2*) (resp+sizeof(IBHpacket));
|
||||
m2->src_conn=pm->src_conn;
|
||||
m2->dst_conn=pm->dst_conn;
|
||||
m2->MPI=pm->MPI;
|
||||
m2->xxx1=0;
|
||||
m2->xxx2=0;
|
||||
m2->xx22=0x22;
|
||||
m2->packetNumber=gpacketNumber;
|
||||
gpacketNumber++;
|
||||
if (p1.param[0]==daveFuncRead) {
|
||||
_daveHandleRead(&p1,&pr);
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==daveFuncWrite) {
|
||||
printf("before _daveHandleWrite() %p\n",m2);
|
||||
_daveHandleWrite(&p1,&pr);
|
||||
printf("after _daveHandleWrite() %p\n",m2);
|
||||
fflush(stdout);
|
||||
haveResp=1;
|
||||
// m2->func=0xf1; //!! guessed
|
||||
printf("after _daveHandleWrite()\n");
|
||||
fflush(stdout);
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
printf("after _daveHandleWrite()\n");
|
||||
fflush(stdout);
|
||||
p2->len=m2->len+7;
|
||||
printf("after _daveHandleWrite()\n");
|
||||
fflush(stdout);
|
||||
} else if (p1.param[0]==240) {
|
||||
printf("PDU function code: %d, negociate PDU len\n",p1.param[0]);
|
||||
// _daveDump("packet:",dc->msgIn,dc->msgIn[2]+8);
|
||||
handleNegociate(&p1,&pr);
|
||||
dc->packetNumber=0;
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x28) {
|
||||
printf("PDU function code: %d, run CPU\n",p1.param[0]);
|
||||
// _daveDump("packet:",dc->msgIn,dc->msgIn[2]+8);
|
||||
handleRun(&p1,&pr,&lost);
|
||||
// dc->packetNumber=0;
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x29) {
|
||||
printf("PDU function code: %d, stop CPU\n",p1.param[0]);
|
||||
// _daveDump("packet:",dc->msgIn,dc->msgIn[2]+8);
|
||||
handleStop(&p1,&pr);
|
||||
dc->packetNumber=0;
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x1d) {
|
||||
handleReadProgram(&p1,&pr);
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x1e) {
|
||||
handleContinueReadProgram(&p1,&pr);
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x1f) {
|
||||
handleEndReadProgram(&p1,&pr);
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x1a) {
|
||||
handleLoadProgram(dc, &p1,&pr,PDUnumber,resp, &lost);
|
||||
haveResp=1;
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
// PDUnumber=lost.PDUnumber;
|
||||
} else if (p1.param[0]==0x1b) {
|
||||
haveResp=handleContLoadProgram(dc, &p1,&pr,PDUnumber,resp, &lost);
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else if (p1.param[0]==0x1c) {
|
||||
handleEndLoadProgram(dc, &p1,&pr,PDUnumber,resp, &lost);
|
||||
haveResp=0;
|
||||
} else if (p1.param[0]==0) {
|
||||
printf("PDU function code: %d, system Messaga ?\n",p1.param[0]);
|
||||
_daveSendMPIAck2(dc);
|
||||
// _daveDump("packet:",b,b[2]+8);
|
||||
haveResp=handleSystemMessage(&p1,&pr);
|
||||
// pr.header[4]=p1.header[4]; // give the PDU a number
|
||||
// pr.header[5]=p1.header[5]; // give the PDU a number
|
||||
m2->func=0xf1; //!! guessed
|
||||
m2->len=pr.hlen+pr.plen+pr.dlen+2;
|
||||
p2->len=m2->len+7;
|
||||
} else {
|
||||
printf("Unsupported PDU function code: %d\n",p1.param[0]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (pm->func==0xb0) {
|
||||
// printf("Ackknowledge for packet number: %d\n",*(dc->msgIn+15));
|
||||
}
|
||||
if (pm->func==0xe0) {
|
||||
printf("Connect to MPI: %d\n",pm->MPI);
|
||||
|
||||
memcpy(resp, r5, sizeof(r5));
|
||||
resp[8]=pm->src_conn;
|
||||
resp[9]=pm->src_conn;
|
||||
resp[10]=pm->MPI;
|
||||
resp[11]=7; //????
|
||||
haveResp=1;
|
||||
}
|
||||
}
|
||||
if (((p->rFlags==0x82) /*||(p->sFlags==0x82)*/)&&(p->packetNumber)&&(p->len)) {
|
||||
// printf("before _daveSendIBHNetAck()\n");
|
||||
fflush(stdout);
|
||||
_daveSendIBHNetAck2(dc);
|
||||
}
|
||||
if (haveResp) {
|
||||
// printf("have response\n");
|
||||
resp[22]=PDUnumber % 256; // test!
|
||||
resp[21]=PDUnumber / 256; // test!
|
||||
|
||||
write(dc->iface->fd.rfd,resp,resp[2]+8);
|
||||
_daveDump("I sent:",resp,resp[2]+8);
|
||||
fflush(stdout);
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct _portInfo {
|
||||
int fd;
|
||||
}portInfo;
|
||||
|
||||
#define mymemcmp _daveMemcmp
|
||||
void *portServer(void *arg)
|
||||
{
|
||||
int waitCount, res, pcount, r2;
|
||||
_daveOSserialType s;
|
||||
daveInterface * di;
|
||||
daveConnection * dc;
|
||||
|
||||
portInfo * pi=(portInfo *) arg;
|
||||
LOG2(ThisModule "portMy fd is:%d\n",
|
||||
pi->fd);
|
||||
FLUSH;
|
||||
waitCount= 0;
|
||||
// daveDebug=daveDebugAll;
|
||||
pcount=0;
|
||||
|
||||
s.rfd=pi->fd;
|
||||
s.wfd=pi->fd;
|
||||
di=daveNewInterface(s,"IF",0,daveProtoMPI_IBH,daveSpeed187k);
|
||||
di->timeout=900000;
|
||||
dc=daveNewConnection(di,0,0,0);
|
||||
di->timeout=1900000;
|
||||
while (waitCount < 1000) {
|
||||
dc->AnswLen=_daveReadIBHPacket(dc->iface, dc->msgIn);
|
||||
if (dc->AnswLen>0) {
|
||||
res=dc->AnswLen;
|
||||
if (daveDebug & daveDebugPacket) {
|
||||
LOG2(ThisModule "%d ", pcount);
|
||||
_daveDump("packet", dc->msgIn, dc->AnswLen);
|
||||
}
|
||||
waitCount = 0;
|
||||
analyze(dc);
|
||||
|
||||
r2=2*res;
|
||||
|
||||
if(r2==sizeof(cha0)) {
|
||||
if (0==mymemcmp(cha0, dc->msgIn, res)) {
|
||||
LOG1(ThisModule "found challenge 0, write response 0\n");
|
||||
write(pi->fd, res0, sizeof(res0));
|
||||
}
|
||||
}
|
||||
if(r2==sizeof(cha1)) {
|
||||
if (0==mymemcmp(cha1, dc->msgIn, res)) {
|
||||
LOG1(ThisModule "found challenge 1, write response 1\n");
|
||||
write(pi->fd, res1, sizeof(res1));
|
||||
}
|
||||
}
|
||||
if(r2==sizeof(cha2)) {
|
||||
if (0==mymemcmp(cha2, dc->msgIn, res)) {
|
||||
LOG1(ThisModule "found challenge 2, write response 2\n");
|
||||
write(pi->fd, res2, sizeof(res2));
|
||||
}
|
||||
}
|
||||
if(r2==sizeof(cha3)) {
|
||||
if (0==mymemcmp(cha3, dc->msgIn, res)) {
|
||||
LOG1(ThisModule "found challenge 3, write response 3\n");
|
||||
res3[8]=dc->msgIn[8];
|
||||
write(pi->fd, res3, sizeof(res3));
|
||||
}
|
||||
}
|
||||
|
||||
if(r2==sizeof(cha8)) {
|
||||
if (0==mymemcmp(cha8, dc->msgIn, res)) {
|
||||
LOG1(ThisModule "found challenge 8, write response 7\n");
|
||||
res7[8]=dc->msgIn[8];
|
||||
res7[9]=dc->msgIn[9];
|
||||
res7[10]=dc->msgIn[10];
|
||||
write(pi->fd, res7, sizeof(res7));
|
||||
}
|
||||
}
|
||||
|
||||
if(r2==sizeof(cha11)) {
|
||||
if (0==mymemcmp(cha11, dc->msgIn, res)) {
|
||||
LOG1(ThisModule "found challenge 11, response 10\n");
|
||||
res10[8]=dc->msgIn[8];
|
||||
res10[9]=dc->msgIn[9];
|
||||
// res10[10]=dc->msgIn[10];
|
||||
// res10[32]=dc->msgIn[28];
|
||||
// res10[34]=dc->msgIn[30];
|
||||
// sendMPIAck2(dc->msgIn, pi->fd, ackPacketNumber);
|
||||
//// dc->needAckNumber=0;
|
||||
//// _daveSendMPIAck2(dc);
|
||||
//// write(pi->fd, res10, sizeof(res10));
|
||||
}
|
||||
}
|
||||
pcount++;
|
||||
} else {
|
||||
waitCount++;
|
||||
}
|
||||
}
|
||||
LOG1(ThisModule "portserver: I closed my fd.\n");
|
||||
FLUSH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This waits in select for a file descriptor from accepter and starts a new child server
|
||||
with this file descriptor.
|
||||
*/
|
||||
int PID;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
portInfo pi;
|
||||
fd_set FDS;
|
||||
int filedes[2], res, newfd;
|
||||
pthread_attr_t attr;
|
||||
pthread_t ac, ps;
|
||||
accepter_info ai;
|
||||
PID=getpid();
|
||||
if (argc<2) {
|
||||
printf("Usage: ibhtest port\n");
|
||||
printf("Example: ibhtest 1099 (used by IBHNetLink)\n");
|
||||
return -1;
|
||||
}
|
||||
readCallBack=dummyRead;
|
||||
writeCallBack=myWrite;
|
||||
|
||||
pipe(filedes);
|
||||
ai.port = atol(argv[1]);
|
||||
LOG2(ThisModule "Main serv: %d\n", ai.port);
|
||||
LOG2(ThisModule "Main serv: Accepter pipe fd: %d\n", ai.fd);
|
||||
ai.fd = filedes[1];
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
||||
res=pthread_create(&ac, &attr, accepter, &ai /*&filedes[1] */ );
|
||||
do {
|
||||
FD_ZERO(&FDS);
|
||||
FD_SET(filedes[0], &FDS);
|
||||
|
||||
LOG2(ThisModule "Main serv: about to select on %d\n",
|
||||
filedes[0]);
|
||||
FLUSH;
|
||||
if (select(filedes[0] + 1, &FDS, NULL, &FDS, NULL) > 0) {
|
||||
LOG1(ThisModule "Main serv: about to read\n");
|
||||
res = read(filedes[0], &pi.fd, sizeof(pi.fd));
|
||||
ps=0;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
||||
res=pthread_create(&ps, &attr, portServer, &pi);
|
||||
if(res) {
|
||||
LOG2(ThisModule
|
||||
"Main serv: create error:%s\n", strerror(res));
|
||||
close(newfd);
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Changes:
|
||||
|
||||
14/07/2003 give a hint about usage
|
||||
02/01/2005 fixed argc, it's 2 if there is 1 argument.
|
||||
03/06/2005 removed byteswap.h, it is not needed.
|
||||
*/
|
||||
435
isotest4.c
Normal file
435
isotest4.c
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
Part of Libnodave, a free communication libray for Siemens S7 300/400.
|
||||
This program simulates a CPx43.
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2002.
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Visual; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "log2.h"
|
||||
|
||||
#define uc unsigned char
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#define ThisModule __FILE__
|
||||
|
||||
#include "accepter.c"
|
||||
//#include <byteswap.h>
|
||||
|
||||
#include "nodave.h"
|
||||
|
||||
#define bSize 1256
|
||||
#define us unsigned short
|
||||
|
||||
#define debug 10
|
||||
|
||||
/*
|
||||
many (1024) bytes. hopefully enough to serve any read request.
|
||||
*/
|
||||
uc dummyRes[1024];
|
||||
|
||||
/*
|
||||
a read callback function
|
||||
*/
|
||||
uc * dummyRead (int area, int DBnumber, int start, int len, int * res) {
|
||||
dummyRes[3]+=5;
|
||||
dummyRes[0]+=5;
|
||||
#if debug>1
|
||||
printf("User callback should deliver pointer to %d bytes from %s %d beginning at %d.\n",
|
||||
len, daveAreaName(area),DBnumber,start);
|
||||
#endif
|
||||
*res=0;
|
||||
|
||||
return dummyRes;
|
||||
};
|
||||
|
||||
void dummyWrite(int area, int DBnumber, int start, int len, int * res, uc*buffer) {
|
||||
// dummyRes[2]++;
|
||||
start/=8;
|
||||
#if debug>1
|
||||
printf("User write callback should write %d bytes from %s %d to address %d.\n",
|
||||
len, daveAreaName(area),DBnumber,start);
|
||||
#endif
|
||||
*res=0;
|
||||
memcpy(dummyRes+start,buffer,len);
|
||||
};
|
||||
|
||||
int handleSystemMessage(PDU * p1,PDU * p2) {
|
||||
int number=0x100*(p1->data[4])+p1->data[5];
|
||||
int count=0x100*(p1->data[6])+p1->data[7];
|
||||
printf("SysMessage number: %d\n",number);
|
||||
printf("count: %d\n",count);
|
||||
if (number==20) {
|
||||
/*
|
||||
Info about CPU resources. I return some strange values in order
|
||||
to watch which number goes where.
|
||||
*/
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x03, 0x00,0x00,0x00,0x00,};
|
||||
uc va[]={
|
||||
// FF,09,00,50,
|
||||
00,0x14,00,00,
|
||||
00,0x08,00,07,
|
||||
0,1,0,1,0,0x81,00,00, // 129 input bytes
|
||||
0,2,0,1,0,0x7f,00,00, // 127 output bytes
|
||||
0,3,0,1,0x0a,00,00,0x80, // 10*32 flag bytes
|
||||
00,04,00,01,00,0x80,00,00, // 128 Timer
|
||||
00,05,00,01,00,0x40,00,0x08, // 64 counter
|
||||
|
||||
00,06,00,01,05,01,00,00, // 5*256+1=1281 log.Address
|
||||
00,07,00,01,06,03,00,00, // 6*256+3=1539 local data
|
||||
00,0x08,00,01,01,00,00,0x10,
|
||||
00,0x09,00,01,00,01,00,00,
|
||||
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
// _daveAddData(p2, p1->data, 8);
|
||||
// p1->data[3]=4; // 4 bytes have been already copied to result string
|
||||
// _daveAddValue(p2, va, sizeof(va));
|
||||
_daveAddUserData(p2, va, sizeof(va));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==292) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x03, 0x00,0x00,0x00,0x00,};
|
||||
uc va[]={
|
||||
0x00,0x14,0x00,0x00,0x43,0x02,0xff,0x68, 0xc7,0x00,0x00,0x00,
|
||||
0x08,0x10,0x77,0x10,0x03,0x07,0x10,0x13, 0x22,0x26,0x58,0x85,
|
||||
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, p1->data, 8);
|
||||
p1->data[3]=4; // 4 bytes have been copied to result string
|
||||
_daveAddValue(p2, va, sizeof(va));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==306) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
uc va306[]={
|
||||
0,40,0,1,0,4,0, 1, 0,0,0,
|
||||
1, 0,2,0,0,0,0,86,86,0,0,
|
||||
0, 0,0,0,0,0,0, 0, 0,0,0,
|
||||
0, 0,0,0,0,0,0, 0, 0,0,0,
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, p1->data, 8);
|
||||
p1->data[3]=4; // 4 bytes have been copied to result string
|
||||
_daveAddValue(p2, va306, sizeof(va306));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==273) { /* read order code (MLFB) */
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x03, 0x00,0x00,0x00,0x00,};
|
||||
uc va273[]={
|
||||
0x00,0x1c,0x00,0x01,0x43,0x02,
|
||||
'6','E','S',
|
||||
// '7',' ','3','1','5','-','2','A','F','0','3','-','0','A','B','0',
|
||||
'7',' ','L','I','B','N','O','D','A','V','E','-','T','.','H','.',
|
||||
' ',0x00,0xc0,0x00,0x02,0x00,0x00,
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, p1->data, 8);
|
||||
p1->data[3]=4; // 4 bytes have already been copied to result string
|
||||
_daveAddValue(p2, va273, sizeof(va273));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==305) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
uc va306[]={
|
||||
// 0,40,0,1,0,4,0, 1, 0,0,0,
|
||||
// 1, 0,2,0,0,0,0,86,86,0,0,
|
||||
// 0, 0,0,0,0,0,0, 0, 0,0,0,
|
||||
// 0, 0,0,0,0,0,0, 0, 0,0,0,
|
||||
0, 40, 0, 1, 0, 2,190,253, 15, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 60, 1,
|
||||
0, 0, 0, 0,125, 0, 0, 5, 3, 4,
|
||||
0, 0, 0, 0, 0, 12, 0, 10, 0, 0,
|
||||
0, 9, 0, 0,
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, p1->data, 8);
|
||||
p1->data[3]=4; // 4 bytes have been copied to result string
|
||||
_daveAddValue(p2, va306, sizeof(va306));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==0) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
uc va[]={
|
||||
// 255,9,0,114,0,0,0,0,
|
||||
0,2,0,53,0,0,15,0,0,17,1,17,15,17,0,18,
|
||||
1,18,15,18,0,19,0,20,0,21,1,21,0,23,1,23,15,
|
||||
23,0,24,1,24,15,24,0,25,15,25,15,26,15,27,0,26,0,
|
||||
27,0,33,10,33,15,33,2,34,0,35,15,35,0,36,1,36,
|
||||
4,36,5,36,1,49,1,50,2,50,0,116,1,116,15,116,12,
|
||||
145,13,145,10,145,0,146,2,146,6,146,15,146,0,177,0,178,0,
|
||||
179,0,180,0,160,1,160,12,139,126,
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, p1->data, 8);
|
||||
p1->data[3]=4; // 4 bytes have been copied to result string
|
||||
_daveAddValue(p2, va, sizeof(va));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else if (number==1060) {
|
||||
uc pa[]={0x00,0x01,0x12,0x08,0x12,0x84,0x01,0x01, 0x00,0x00,0x00,0x00,};
|
||||
uc va[]={
|
||||
// 255,9,0,114,0,0,0,0,
|
||||
0,20,0,1,81,68,255,8,0,0,0,0,0,0,0,0,148,1,2,22,83,88,104,17,
|
||||
};
|
||||
_daveInitPDUheader(p2,7);
|
||||
_daveAddParam(p2, pa, sizeof(pa));
|
||||
_daveAddData(p2, p1->data, 8);
|
||||
p1->data[3]=4; // 4 bytes have been copied to result string
|
||||
_daveAddValue(p2, va, sizeof(va));
|
||||
_daveDumpPDU(p2);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
};
|
||||
|
||||
int gpacketNumber=0;
|
||||
|
||||
typedef struct{
|
||||
uc prot;
|
||||
uc ch1;
|
||||
uc ch2;
|
||||
uc len;
|
||||
uc xxxx1;
|
||||
uc func;
|
||||
uc xxxx2;
|
||||
} ISOpacket;
|
||||
|
||||
void analyze(daveConnection * dc) {
|
||||
ISOpacket * p,* p2;
|
||||
uc resp[2000];
|
||||
uc r5[]={
|
||||
0x03,0x00,0x00,0x16,
|
||||
0x11,0xd0,
|
||||
0,0,0,1,0,
|
||||
0xc0,1,9,
|
||||
0x0c1,2,1,2,
|
||||
0x0c2,2,1,0,
|
||||
};
|
||||
|
||||
int haveResp=0;
|
||||
PDU p1,pr;
|
||||
p= (ISOpacket*) dc->msgIn;
|
||||
dc->needAckNumber=-1; // Assume no ack
|
||||
#if debug>1
|
||||
printf("Protocol: %d\n",p->ch1);
|
||||
printf("Channel: %d\n",p->ch1);
|
||||
printf("Channel: %d\n",p->ch2);
|
||||
printf("Length: %d\n",p->len);
|
||||
printf("(MPI) func:%d\n",p->func);
|
||||
#endif
|
||||
if (p->func==0xf0) {
|
||||
#if debug>1
|
||||
printf("0xf0:PDU transport\n");
|
||||
#endif
|
||||
// p1.header=((uc*)p)+sizeof(ISOpacket);
|
||||
dc->PDUstartI=sizeof(ISOpacket);
|
||||
_daveSetupReceivedPDU(dc, &p1);
|
||||
#if debug>1
|
||||
_daveDumpPDU(&p1);
|
||||
#endif
|
||||
pr.header=resp+sizeof(ISOpacket);
|
||||
p2= (ISOpacket*) resp;
|
||||
p2->ch1=p->ch2;
|
||||
p2->ch2=p->ch1;
|
||||
if (p1.param[0]==daveFuncRead) {
|
||||
_daveHandleRead(&p1,&pr);
|
||||
haveResp=1;
|
||||
p2->len=pr.hlen+pr.plen+pr.dlen+7;
|
||||
} else if (p1.param[0]==daveFuncWrite) {
|
||||
_daveHandleWrite(&p1,&pr);
|
||||
haveResp=1;
|
||||
p2->len=pr.hlen+pr.plen+pr.dlen+7;
|
||||
} else if (p1.param[0]==240) {
|
||||
printf("PDU function code: %d, negociate PDU len\n",p1.param[0]);
|
||||
_daveDump("packet:",dc->msgIn,dc->msgIn[3]);
|
||||
memcpy(resp, dc->msgIn, dc->msgIn[3]);
|
||||
resp[23]=960 / 0x100;
|
||||
resp[24]=960 % 0x100;
|
||||
haveResp=1;
|
||||
} else if (p1.param[0]==0) {
|
||||
printf("PDU function code: %d, system Message ?\n",p1.param[0]);
|
||||
haveResp=handleSystemMessage(&p1,&pr);
|
||||
pr.header[4]=p1.header[4]; // give the PDU a number
|
||||
haveResp=1;
|
||||
p2->len=pr.hlen+pr.plen+pr.dlen+7;
|
||||
} else {
|
||||
printf("Unsupported PDU function code: %d\n",p1.param[0]);
|
||||
}
|
||||
}
|
||||
if (p->func==0xe0) {
|
||||
int rack=*(dc->msgIn+17)-1;
|
||||
int slot=*(dc->msgIn+18);
|
||||
printf("Connect to rack:%d slot:%d \n", rack, slot);
|
||||
|
||||
*(r5+16)=rack+1;
|
||||
*(r5+17)=slot;
|
||||
memcpy(resp, r5, sizeof(r5));
|
||||
haveResp=1;
|
||||
}
|
||||
if (haveResp) {
|
||||
// simulating CP response delay:
|
||||
usleep(10000);
|
||||
//#define sim_broken_transport
|
||||
#undef sim_broken_transport
|
||||
#ifdef sim_broken_transport
|
||||
double pr=random();
|
||||
pr/=RAND_MAX;
|
||||
|
||||
if (pr>=0.90) {
|
||||
LOG2("faking broken transport: %0.2f >= 0.95 \n",pr);
|
||||
} else
|
||||
write(dc->iface->fd.wfd,resp,resp[3]);
|
||||
#else
|
||||
write(dc->iface->fd.wfd,resp,resp[3]);
|
||||
#endif
|
||||
#if debug >1
|
||||
_daveDump("I send:",resp,resp[3]);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct _portInfo {
|
||||
int fd;
|
||||
}portInfo;
|
||||
|
||||
#define mymemcmp _daveMemcmp
|
||||
void *portServer(void *arg)
|
||||
{
|
||||
_daveOSserialType s;
|
||||
daveInterface * di;
|
||||
daveConnection * dc;
|
||||
int waitCount,res,pcount;
|
||||
portInfo * pi=(portInfo *) arg;
|
||||
LOG2("portServer: My fd is:%d\n", pi->fd);
|
||||
FLUSH;
|
||||
waitCount = 0;
|
||||
daveSetDebug(0);//daveDebugAll;
|
||||
pcount=0;
|
||||
|
||||
s.rfd=pi->fd;
|
||||
s.wfd=pi->fd;
|
||||
di =daveNewInterface(s,"IF1",0,daveProtoISOTCP,daveSpeed187k);
|
||||
di->timeout=900000;
|
||||
dc=daveNewConnection(di,2,0,2);
|
||||
while (waitCount < 100) {
|
||||
dc->AnswLen=_daveReadISOPacket(dc->iface, dc->msgIn);
|
||||
if (dc->AnswLen>0) {
|
||||
res=dc->AnswLen;
|
||||
#if debug>1
|
||||
LOG2( "%d ", pcount);
|
||||
_daveDump("packet", dc->msgIn, dc->AnswLen);
|
||||
#endif
|
||||
waitCount = 0;
|
||||
analyze(dc);
|
||||
pcount++;
|
||||
} else {
|
||||
waitCount++;
|
||||
}
|
||||
}
|
||||
LOG1( "portServer: I closed my fd.\n");
|
||||
FLUSH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This waits in select for a file descriptor from accepter and starts a new child server
|
||||
with this file descriptor.
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// int PID=getpid();
|
||||
portInfo pi;
|
||||
int filedes[2], res, newfd;
|
||||
fd_set FDS;
|
||||
char * s2;
|
||||
pthread_attr_t attr;
|
||||
pthread_t ac, ps;
|
||||
accepter_info ai;
|
||||
|
||||
printf("CP-Simulation for ISO over TCP\n");
|
||||
if (argc<2) {
|
||||
printf("Assuming standard port (102) for ISO over TCP\n");
|
||||
printf("If you don't want that do: isotest4 xxx, and I will listen on xxx.\n\n");
|
||||
s2 = "102 ";
|
||||
} else
|
||||
s2 = argv[1];
|
||||
printf("Assuming rack 0, slot 2 for simulated device. There's currently no way to change that.\n\n");
|
||||
readCallBack=dummyRead;
|
||||
writeCallBack=dummyWrite;
|
||||
|
||||
|
||||
pipe(filedes);
|
||||
ai.port = atol(s2);
|
||||
LOG2( "Main serv: port: %d\n", ai.port);
|
||||
ai.fd = filedes[1];
|
||||
LOG2( "Main serv: Accepter pipe fd: %d\n", ai.fd);
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
||||
res=pthread_create(&ac, &attr, accepter, &ai /*&filedes[1] */ );
|
||||
do {
|
||||
FD_ZERO(&FDS);
|
||||
FD_SET(filedes[0], &FDS);
|
||||
|
||||
LOG2( "Main serv: about to select on %d\n",
|
||||
filedes[0]);
|
||||
FLUSH;
|
||||
if (select(filedes[0] + 1, &FDS, NULL, &FDS, NULL) > 0) {
|
||||
LOG1( "Main serv: about to read\n");
|
||||
res = read(filedes[0], &pi.fd, sizeof(pi.fd));
|
||||
ps=0;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
||||
res=pthread_create(&ps, &attr, portServer, &pi);
|
||||
if(res) {
|
||||
LOG2( "Main serv: create error:%s\n", strerror(res));
|
||||
close(newfd);
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Changes:
|
||||
|
||||
14/07/2003 give a hint about usage
|
||||
08/04/2004 Logging for multithreaded things now uses PID, which is set in thread creation
|
||||
*/
|
||||
191
libnodave.DEF
Normal file
191
libnodave.DEF
Normal file
@@ -0,0 +1,191 @@
|
||||
LIBRARY
|
||||
EXPORTS
|
||||
__daveAnalyze
|
||||
__daveAnalyzePPI
|
||||
_daveAddData
|
||||
_daveAddParam
|
||||
_daveAddUserData
|
||||
_daveAddValue
|
||||
_daveConnectPLCMPI1
|
||||
_daveConnectPLCMPI2
|
||||
_daveConnectPLCPPI
|
||||
_daveConnectPLCTCP
|
||||
_daveConnectPLC_IBH
|
||||
_daveConstructBadReadResponse
|
||||
_daveConstructDoUpload
|
||||
_daveConstructEndUpload
|
||||
_daveConstructReadResponse
|
||||
_daveConstructUpload
|
||||
_daveConstructWriteResponse
|
||||
_daveDisconnectAdapterMPI
|
||||
_daveDisconnectPLCMPI
|
||||
_daveDisconnectPLC_IBH
|
||||
_daveDump
|
||||
_daveDumpPDU
|
||||
_daveExchange
|
||||
_daveExchangeIBH
|
||||
_daveExchangeMPI
|
||||
_daveExchangePPI
|
||||
_daveExchangePPI_IBH
|
||||
_daveExchangeTCP
|
||||
_daveGetAck
|
||||
_daveGetResponseISO_TCP
|
||||
_daveGetResponseMPI
|
||||
_daveGetResponseMPI_IBH
|
||||
_daveGetResponsePPI
|
||||
_daveGetResponsePPI_IBH
|
||||
_daveHandleRead
|
||||
_daveHandleWrite
|
||||
_daveIncMessageNumber
|
||||
_daveInitAdapterMPI1
|
||||
_daveInitAdapterMPI2
|
||||
_daveInitPDUheader
|
||||
_daveInitStepIBH
|
||||
_daveListReachablePartnersDummy
|
||||
_daveListReachablePartnersMPI
|
||||
_daveListReachablePartnersMPI_IBH
|
||||
_daveMemcmp
|
||||
_daveNegPDUlengthRequest
|
||||
_davePackPDU
|
||||
_davePackPDU_PPI
|
||||
_daveReadChars2
|
||||
_daveReadIBHPacket
|
||||
_daveReadISOPacket
|
||||
_daveReadMPI2
|
||||
_daveReadMPINLpro
|
||||
_daveReadMPI
|
||||
_daveReadOne
|
||||
_daveReadSingle
|
||||
_daveReturnOkDummy2
|
||||
_daveReturnOkDummy
|
||||
_daveSendAck
|
||||
_daveSendDialog2
|
||||
_daveSendIBHNetAck
|
||||
_daveSendIBHNetAckPPI
|
||||
_daveSendIt
|
||||
_daveSendLength
|
||||
_daveSendMPIAck2
|
||||
_daveSendMPIAck_IBH
|
||||
_daveSendMessageMPI
|
||||
_daveSendMessageMPI_IBH
|
||||
_daveSendRequestData
|
||||
_daveSendSingle
|
||||
_daveSendWithCRC
|
||||
_daveSendWithPrefix2
|
||||
_daveSendWithPrefix
|
||||
_daveSetupReceivedPDU
|
||||
_daveTestPGReadResult
|
||||
_daveTestReadResult
|
||||
_daveTestResultData
|
||||
_daveTestWriteResult
|
||||
_daveWriteIBH
|
||||
closePort
|
||||
closeSocket
|
||||
closeS7online
|
||||
daveAddBitVarToReadRequest
|
||||
daveAddBitVarToWriteRequest
|
||||
daveAddToReadRequest
|
||||
daveAddVarToReadRequest
|
||||
daveAddVarToWriteRequest
|
||||
daveAreaName
|
||||
daveBlockName
|
||||
daveBuildAndSendPDU
|
||||
daveClrBit
|
||||
daveCopyRAMtoROM
|
||||
daveConnectPLC
|
||||
daveDisconnectAdapter
|
||||
daveDisconnectPLC
|
||||
daveExecReadRequest
|
||||
daveExecWriteRequest
|
||||
daveForce200
|
||||
daveForceDisconnectIBH
|
||||
daveFree
|
||||
daveFreeResults
|
||||
daveFromBCD
|
||||
daveGetAnswLen
|
||||
daveGetBlockInfo
|
||||
daveGetCounterValue
|
||||
daveGetCounterValueAt
|
||||
daveGetDebug
|
||||
daveGetErrorOfResult
|
||||
daveGetFloat
|
||||
daveGetFloatAt
|
||||
daveGetFloatfrom
|
||||
daveGetMPIAdr
|
||||
daveGetMaxPDULen
|
||||
daveGetName
|
||||
daveGetOrderCode
|
||||
daveGetPDUerror
|
||||
daveGetProgramBlock
|
||||
daveGetResponse
|
||||
daveGetS16
|
||||
daveGetS16At
|
||||
daveGetS16from
|
||||
daveGetS32
|
||||
daveGetS32At
|
||||
daveGetS32from
|
||||
daveGetS8
|
||||
daveGetS8At
|
||||
daveGetS8from
|
||||
daveGetSeconds
|
||||
daveGetSecondsAt
|
||||
daveGetTimeout
|
||||
daveGetU16
|
||||
daveGetU16At
|
||||
daveGetU16from
|
||||
daveGetU32
|
||||
daveGetU32At
|
||||
daveGetU32from
|
||||
daveGetU8
|
||||
daveGetU8At
|
||||
daveGetU8from
|
||||
daveInitAdapter
|
||||
daveListBlocks
|
||||
daveListBlocksOfType
|
||||
daveListReachablePartners
|
||||
daveNewConnection
|
||||
daveNewInterface
|
||||
daveNewPDU
|
||||
daveNewResultSet
|
||||
davePascalNewInterface
|
||||
davePrepareReadRequest
|
||||
davePrepareWriteRequest
|
||||
davePut16
|
||||
davePut16At
|
||||
davePut32
|
||||
davePut32At
|
||||
davePut8
|
||||
davePut8At
|
||||
davePutFloat
|
||||
davePutFloatAt
|
||||
daveReadBits
|
||||
daveReadBytes
|
||||
daveReadManyBytes
|
||||
daveReadPLCTime
|
||||
daveReadSZL
|
||||
daveResetIBH
|
||||
daveSendMessage
|
||||
daveSetBit
|
||||
daveSetDebug
|
||||
daveSetPLCTime
|
||||
daveSetPLCTimeToSystime
|
||||
daveSetTimeout
|
||||
daveStart
|
||||
daveStop
|
||||
daveStrerror
|
||||
daveStringCopy
|
||||
daveSwapIed_16
|
||||
daveSwapIed_32
|
||||
daveToBCD
|
||||
daveToPLCfloat
|
||||
daveUseResult
|
||||
daveWriteBits
|
||||
daveWriteBytes
|
||||
daveWriteManyBytes
|
||||
doUpload
|
||||
endUpload
|
||||
initUpload
|
||||
openS7online
|
||||
openSocket
|
||||
setPort
|
||||
toPLCfloat
|
||||
18
loadPLC
Executable file
18
loadPLC
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
MPI="2";
|
||||
for a in SDB*.mc7; do
|
||||
echo $a;
|
||||
./testMPIload --mpi=$MPI /dev/ttyS0 $a
|
||||
done;
|
||||
for a in DB*.mc7; do
|
||||
echo $a;
|
||||
./testMPIload --mpi=$MPI /dev/ttyS0 $a
|
||||
done;
|
||||
for a in FC*.mc7; do
|
||||
echo $a;
|
||||
./testMPIload --mpi=$MPI /dev/ttyS0 $a
|
||||
done;
|
||||
for a in OB*.mc7; do
|
||||
echo $a;
|
||||
./testMPIload --mpi=$MPI /dev/ttyS0 $a
|
||||
done;
|
||||
57
log2.h
Normal file
57
log2.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef __log
|
||||
#define __log
|
||||
|
||||
#ifdef LINUX
|
||||
#define HAVE_PRINTF
|
||||
#define logout stdout
|
||||
#endif
|
||||
|
||||
#ifdef BCCWIN
|
||||
#define HAVE_PRINTF
|
||||
#define logout stdout
|
||||
#endif
|
||||
|
||||
#ifdef KEILC51
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DOS
|
||||
#define HAVE_PRINTF
|
||||
#define logout stdout
|
||||
#endif
|
||||
|
||||
#ifdef AVR
|
||||
#define NO_PRINT_CODE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_PRINTF
|
||||
#define LOG1(x) fprintf(logout,x)
|
||||
#define LOG2(x,y) fprintf(logout,x,y)
|
||||
#define LOG3(a,b,c) fprintf(logout,a,b,c)
|
||||
#define LOG4(a,b,c,d) fprintf(logout,a,b,c,d)
|
||||
#define LOG5(a,b,c,d,e) fprintf(logout,a,b,c,d,e)
|
||||
#define LOG6(a,b,c,d,e,f) fprintf(logout,a,b,c,d,e,f)
|
||||
#define LOG7(a,b,c,d,e,f,g) fprintf(logout,a,b,c,d,e,f,g)
|
||||
#define FLUSH fflush(logout)
|
||||
|
||||
#define LOG_1(a) fprintf(logout,a)
|
||||
#define LOG_2(a,b) fprintf(logout,a,b)
|
||||
#endif /* HAVE_PRINTF */
|
||||
|
||||
#ifdef NO_PRINT_CODE
|
||||
#define LOG1(x)
|
||||
#define LOG2(x,y)
|
||||
#define LOG3(a,b,c)
|
||||
#define LOG4(a,b,c,d)
|
||||
#define LOG5(a,b,c,d,e)
|
||||
#define LOG6(a,b,c,d,e,f)
|
||||
#define LOG7(a,b,c,d,e,f,g)
|
||||
#define FLUSH
|
||||
|
||||
#define LOG_1(a)
|
||||
#define LOG_2(a,b)
|
||||
#endif /* NO_PRINT_CODE */
|
||||
|
||||
|
||||
#endif /* __log */
|
||||
77
makefile.mak
Normal file
77
makefile.mak
Normal file
@@ -0,0 +1,77 @@
|
||||
#
|
||||
# Makefile to build a Windows Version of LIBNODAVE using the free command line tools
|
||||
# from Borland.
|
||||
#
|
||||
# type 'make' to build libnodave.dll and some statically linked test programs.
|
||||
# type 'make dynamic' to make libnodave.dll and some dynamically linked test programs.
|
||||
#
|
||||
# The directory where the tools are:
|
||||
#
|
||||
BCCPATH=../bin
|
||||
CC=$(BCCPATH)/bcc32
|
||||
LL=$(BCCPATH)/ilink32
|
||||
|
||||
CFLAGS= -I..\include -c -DBCCWIN -DDAVE_LITTLE_ENDIAN
|
||||
|
||||
PROGRAMS=testMPI.exe testPPI.exe \
|
||||
testPPI_IBH.exe testPPI_IBHload.exe testPPIload.exe \
|
||||
testMPIload.exe testISO_TCP.exe testISO_TCPload.exe testIBH.exe testMPI_IBHload.exe
|
||||
|
||||
|
||||
DYNAMIC_PROGRAMS=testMPId.exe testPPId.exe testISO_TCPd.exe testIBHd.exe testPPI_IBHd.exe
|
||||
|
||||
LIBRARIES=libnodave.dll
|
||||
|
||||
all: $(PROGRAMS) $(LIBRARIES)
|
||||
|
||||
dynamic: $(DYNAMIC_PROGRAMS)
|
||||
|
||||
testISO_TCP.exe: nodave.obj openSocketw.obj testISO_TCP.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 testISO_TCP.obj openSocketw.obj nodave.obj, testISO_TCP.exe,,CW32 IMPORT32
|
||||
testMPI.exe: setportw.obj nodave.obj testMPI.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 setportw.obj nodave.obj testMPI.obj, testMPI.exe,,CW32 IMPORT32 ws2_32
|
||||
testIBH.exe: openSocketw.obj nodave.obj testIBH.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 openSocketw.obj nodave.obj testIBH.obj, testIBH.exe,,CW32 IMPORT32 ws2_32
|
||||
|
||||
testIBHd.exe: libnodave.dll testIBH.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 testIBH.obj, testIBHd.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
|
||||
testPPI_IBH.exe: openSocketw.obj nodave.obj testPPI_IBH.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 openSocketw.obj nodave.obj testPPI_IBH.obj, testPPI_IBH.exe,,CW32 IMPORT32 ws2_32
|
||||
|
||||
testPPI_IBHd.exe: libnodave.dll testPPI_IBH.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 testPPI_IBH.obj, testPPI_IBHd.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
|
||||
testMPId.exe: libnodave.dll testMPI.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 testMPI.obj , testMPId.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
testPPI.exe: testPPI.obj nodave.obj setportw.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 setportw.obj nodave.obj testPPI.obj, testPPI.exe,,CW32 IMPORT32
|
||||
testPPId.exe: libnodave.dll testPPI.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 testPPI.obj, testPPId.exe,,libnodave CW32 IMPORT32 ws2_32
|
||||
testISO_TCPd.exe: libnodave.dll testISO_TCP.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 testISO_TCP.obj, testISO_TCPd.exe,,CW32 IMPORT32 ws2_32 libnodave.lib
|
||||
testPPIload.exe: nodave.obj setportw.obj testPPIload.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 setportw.obj nodave.obj testPPIload.obj, testPPIload.exe,,CW32 IMPORT32
|
||||
testMPIload.exe: nodave.obj setportw.obj testMPIload.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 setportw.obj nodave.obj testMPIload.obj, testMPIload.exe,,CW32 IMPORT32
|
||||
testISO_TCPload.exe: nodave.obj openSocketw.obj testISO_TCPload.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 openSocketw.obj nodave.obj testISO_TCPload.obj, testISO_TCPload.exe,,CW32 IMPORT32
|
||||
|
||||
testMPI_IBHload.exe: nodave.obj openSocketw.obj testMPI_IBHload.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 openSocketw.obj nodave.obj testMPI_IBHload.obj, testMPI_IBHload.exe,,CW32 IMPORT32
|
||||
|
||||
testPPI_IBHload.exe: nodave.obj openSocketw.obj testPPI_IBHload.obj
|
||||
$(LL) /r /Tpe /L..\lib ..\lib\c0x32 openSocketw.obj nodave.obj testPPI_IBHload.obj, testPPI_IBHload.exe,,CW32 IMPORT32
|
||||
|
||||
libnodave.dll: nodave.obj setportw.obj openSocketw.obj
|
||||
$(LL) /v /C /Gn /w /Gk /r /Tpd /L..\lib ..\lib\c0d32 nodave setportw openSocketw , libnodave.dll,,IMPORT32 CW32
|
||||
$(BCCPATH)/implib libnodave.lib libnodave.dll
|
||||
#
|
||||
# delete all but the sources:
|
||||
#
|
||||
clean:
|
||||
del /f /q *.tds *.il? *.obj *.map *.lib *.dll *.exe *.exp
|
||||
#
|
||||
# delete all but what is needed for distribution:
|
||||
#
|
||||
distclean:
|
||||
93
makefile.vc
Normal file
93
makefile.vc
Normal file
@@ -0,0 +1,93 @@
|
||||
#
|
||||
# Makefile to build a Windows Version of LIBNODAVE using MSVC++ from Microsoft.
|
||||
#
|
||||
# type 'make' to build libnodave.dll and some statically linked test programs.
|
||||
# type 'make dynamic' to make libnodave.dll and some dynamically linked test programs.
|
||||
#
|
||||
# The directory where the tools are:
|
||||
#
|
||||
VCPATH=d:\programme\microsoft visual C++ Toolkit 2003
|
||||
SDKPATH=d:\programme\microsoft platform sdk
|
||||
|
||||
VCPATH=c:\programme\microsoft visual Studio 9.0\vc
|
||||
SDKPATH=c:\programme\microsoft sdks\windows\v6.0a
|
||||
|
||||
|
||||
CC="$(VCPATH)\bin\cl"
|
||||
LL="$(VCPATH)\bin\link"
|
||||
|
||||
CFLAGS= -I"$(VCPATH)\include" -I"$(SDKPATH)\include" -c -DBCCWIN -DDAVE_LITTLE_ENDIAN -TC
|
||||
LFLAGS= /LIBPATH:"$(VCPATH)"\lib,"$(SDKPATH)"\lib
|
||||
LLFLAGS = /LIBPATH:"$(VCPATH)\lib" /DEF:libnodave.DEF
|
||||
|
||||
PROGRAMS=testMPI.exe testPPI.exe testAS511.exe\
|
||||
testPPI_IBH.exe testPPI_IBHload.exe testPPIload.exe \
|
||||
testMPIload.exe testISO_TCP.exe testISO_TCPload.exe testIBH.exe testMPI_IBHload.exe \
|
||||
testNLpro.exe testS7online.exe
|
||||
|
||||
|
||||
DYNAMIC_PROGRAMS=testMPId.exe testPPId.exe testISO_TCPd.exe testIBHd.exe testPPI_IBHd.exe
|
||||
|
||||
LIBRARIES=libnodave.dll
|
||||
|
||||
all: $(PROGRAMS) $(LIBRARIES)
|
||||
|
||||
dynamic: $(DYNAMIC_PROGRAMS)
|
||||
|
||||
testISO_TCP.exe: nodave.obj openSocketw.obj testISO_TCP.obj
|
||||
$(LL) $(LFLAGS) testISO_TCP.obj openSocketw.obj nodave.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testISO_TCP.exe
|
||||
testMPI.exe: setportw.obj nodave.obj testMPI.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testMPI.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testMPI.exe
|
||||
testIBH.exe: openSocketw.obj nodave.obj testIBH.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testIBH.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testIBH.exe
|
||||
testIBHd.exe: libnodave.dll testIBH.obj
|
||||
$(LL) $(LFLAGS) testIBH.obj libnodave.lib /OUT:testIBHd.exe
|
||||
testPPI_IBH.exe: openSocketw.obj nodave.obj testPPI_IBH.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testPPI_IBH.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testPPI_IBH.exe
|
||||
testPPI_IBHd.exe: libnodave.dll testPPI_IBH.obj
|
||||
$(LL) $(LFLAGS) testPPI_IBH.obj libnodave.lib /OUT:testPPI_IBHd.exe
|
||||
testMPId.exe: libnodave.dll testMPI.obj
|
||||
$(LL) $(LFLAGS) testMPI.obj libnodave.lib /OUT:testMPId.exe
|
||||
testPPI.exe: testPPI.obj nodave.obj setportw.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testPPI.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testPPI.exe
|
||||
testPPId.exe: libnodave.dll testPPI.obj
|
||||
$(LL) $(LFLAGS) testPPI.obj libnodave.lib /OUT:testPPId.exe
|
||||
testISO_TCPd.exe: libnodave.dll testISO_TCP.obj
|
||||
$(LL) $(LFLAGS) testISO_TCP.obj libnodave.lib /OUT:testISO_TCPd.exe
|
||||
testPPIload.exe: nodave.obj setportw.obj testPPIload.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testPPIload.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testPPIload.exe
|
||||
testMPIload.exe: nodave.obj setportw.obj testMPIload.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testMPIload.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testMPIload.exe
|
||||
testISO_TCPload.exe: nodave.obj openSocketw.obj testISO_TCPload.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testISO_TCPload.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testISO_TCPload.exe
|
||||
testMPI_IBHload.exe: nodave.obj openSocketw.obj testMPI_IBHload.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testMPI_IBHload.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testMPI_IBHload.exe
|
||||
testPPI_IBHload.exe: nodave.obj openSocketw.obj testPPI_IBHload.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testPPI_IBHload.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:testPPI_IBHload.exe
|
||||
testAS511.exe: testAS511.obj nodave.obj setportw.obj
|
||||
$(LL) $(LFLAGS) setportw.obj nodave.obj testAS511.obj "$(SDKPATH)"\lib\ws2_32.lib /out:$@
|
||||
testNLpro.exe: testNLpro.obj nodave.obj openSocketw.obj
|
||||
$(LL) $(LFLAGS) openSocketw.obj nodave.obj testNLpro.obj "$(SDKPATH)"\lib\ws2_32.lib /out:$@
|
||||
libnodave.dll: nodave.obj setportw.obj openSocketw.obj openS7online.obj
|
||||
$(LL) $(LLFLAGS) /DLL nodave.obj setportw.obj openSocketw.obj openS7online.obj "$(SDKPATH)"\lib\ws2_32.lib /OUT:libnodave.dll
|
||||
testS7online.exe: testS7online.obj nodave.obj openS7online.obj
|
||||
$(LL) $(LFLAGS) nodave.obj testS7online.obj openS7online.obj "$(SDKPATH)"\lib\ws2_32.lib "$(SDKPATH)"\lib\user32.lib /out:$@
|
||||
|
||||
#
|
||||
# delete all but the sources:
|
||||
#
|
||||
clean:
|
||||
del /f /q *.tds *.il? *.obj *.map *.lib *.dll *.exe *.exp
|
||||
distclean:
|
||||
del /f /q *.tds *.il? *.obj *.map
|
||||
|
||||
nodave.obj: nodave.c nodave.h
|
||||
$(CC) $(CFLAGS) -DDOEXPORT nodave.c
|
||||
setportw.obj: setportw.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT setportw.c
|
||||
openSocketw.obj: openSocketw.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT openSocketw.c
|
||||
openS7online.obj: openS7online.c openS7online.h
|
||||
$(CC) $(CFLAGS) -DDOEXPORT openS7online.c
|
||||
s7fake.obj: s7fake.c
|
||||
$(CC) $(CFLAGS) -DDOEXPORT s7fake.c
|
||||
149
nodaveext.c
Normal file
149
nodaveext.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "nodave.h"
|
||||
char * DECL2 daveStrerrorExt(int code) {
|
||||
switch (code) {
|
||||
case 0x8001: return "Der angeforderte Dienst kann im derzeitigen Zustand der Baugruppe nicht ausgefuehrt werden. Weitere Bausteinfunktionen sind deshalb nicht moeglich.";
|
||||
case 0x8003: return "S7-Protokollfehler. Es ist ein Fehler beim Uebertragen des Bausteins aufgetreten.";
|
||||
|
||||
case 0x8101: return "Applikation, allgemeiner Fehler: Dienst ist der remoten Baugruppe unbekannt.";
|
||||
case 0x8104: return "Der Dienst ist auf der Baugruppe nicht implementiert oder es wird ein Telegrammfehler gemeldet.";
|
||||
|
||||
case 0x8204: return "Die Typangabe zum Objekt ist inkonsistent.";
|
||||
case 0x8205: return "Ein kopierter Baustein ist bereits vorhanden und nicht eingekettet.";
|
||||
|
||||
case 0x8301: return "Der Speicherplatz oder der Arbeitsspeicher auf der Baugruppe ist nicht ausreichend bzw. das angegebene Speichermedium ist nicht erreichbar.";
|
||||
case 0x8302: return "Es liegt ein Ressourcen-Engpass vor bzw. die Prozessor-Ressourcen sind nicht verfuegbar.";
|
||||
case 0x8304: return "Es ist kein weiterer Hochladevorgang mehr moeglich. Es liegt ein Ressourcen-Engpass vor.";
|
||||
case 0x8305: return "Die Funktionalitaet ist nicht verfuegbar.";
|
||||
case 0x8306: return "Arbeitsspeicher nicht ausreichend (bai kopieren, Einketten, AWP laden).";
|
||||
case 0x8307: return "Remanenter Teil des Arbeitsspeichers nicht ausreichend (bai kopieren, Einketten, AWP laden).";
|
||||
|
||||
case 0x8401: return "S7-Protokollfehler: Falsche Reihenfolge der Dienste (z.B. beim Laden oder Hochladen eines Bausteins).";
|
||||
case 0x8402: return "Dienst kann wegen des Zustands des adressierten Objekts nicht ausgefuehrt werden.";
|
||||
case 0x8404: return "S7-Protokoll: Die Funktion kann nicht ausgefuehrt werden.";
|
||||
case 0x8405: return "Der remote Baustein ist im Zustand DISABLE (PBK).Die Funktion kann nicht ausgefuehrt werden.";
|
||||
|
||||
case 0x8500: return "S7-Protokollfehler: Falsche Telegramme.";
|
||||
case 0x8503: return "Meldung von der Baugruppe: Der Dienst wurde vorzeitig abgebrochen.";
|
||||
|
||||
case 0x8701: return "Fehler bei der Adressierung des Objekts im Kommunikationspartner(z.B. Bereichslaengenfehler).";
|
||||
case 0x8702: return "Der angeforderte Dienst wird von der Baugruppe nicht unterstuetzt.";
|
||||
case 0x8703: return "Der Zugriff auf das Objekt wurde abgelehnt.";
|
||||
case 0x8704: return "Zugriffsfehler: Das Objekt ist zerstoert.";
|
||||
|
||||
case 0xd001: return "Protokollfehler: Die Auftragsnummer ist unzulaessig.";
|
||||
case 0xd002: return "Parameterfehler: Die Auftragsvariante ist unzulaessig.";
|
||||
case 0xd003: return "Parameterfehler: Die Testfunktion wird von der Baugruppe nicht unterstuetzt.";
|
||||
case 0xd004: return "Parameterfehler: Der Auftragsstatus ist unzulaessig.";
|
||||
case 0xd005: return "Parameterfehler: Die Auftragsbeendung ist unzulaessig.";
|
||||
case 0xd006: return "Parameterfehler: Die Kennung fuer den Verbindungsabbruch ist unzulaessig.";
|
||||
case 0xd007: return "Parameterfehler: Die Anzahl der Pufferelemente ist unzulaessig.";
|
||||
case 0xd008: return "Parameterfehler: Der Untersetzungsfaktor ist unzulaessig.";
|
||||
case 0xd009: return "Parameterfehler: Die Ausfuehrungsanzahl ist unzulaessig.";
|
||||
case 0xd00a: return "Parameterfehler: Das Triggerereignis ist unzulaessig.Bitte pruefen Sie, ob der angegebene Trigger auf dieser Baugruppe zulaessig ist.";
|
||||
case 0xd00b: return "Parameterfehler: Das Triggerbedingung ist unzulaessig.Bitte pruefen Sie, ob der angegebene Trigger auf dieser Baugruppe zulaessig ist.";
|
||||
|
||||
case 0xd011: return "Parameterfehler im Pfad der Aufrufumgebung: Der Baustein ist nicht vorhanden.";
|
||||
case 0xd012: return "Parameterfehler: Falsche Adresse im Baustein.";
|
||||
case 0xd014: return "Parameterfehler: Der Baustein wird gerade geloescht/ueberladen.";
|
||||
case 0xd015: return "Parameterfehler: Die Variablenadresse ist unzulaessig.";
|
||||
case 0xd016: return "Parameterfehler: Testauftraege nicht moeglich, da Anwenderprogramm fehlerhaft.";
|
||||
case 0xd017: return "Parameterfehler: Die Triggernummer ist unzulaessig.";
|
||||
|
||||
case 0xd025: return "Parameterfehler: Der Pfad ist unzulaessig.";
|
||||
case 0xd026: return "Parameterfehler: Die Zugriffsart ist unzulaessig.";
|
||||
case 0xd027: return "Parameterfehler: Die Anzahl der DBs ist unzulaessig.";
|
||||
|
||||
case 0xd031: return "interner Protokollfehler.";
|
||||
case 0xd032: return "Parameterfehler: Falsche Laenge des Ergebnispuffers.";
|
||||
case 0xd033: return "Parameterfehler: Die Auftragslaenge ist unzulaessig.";
|
||||
|
||||
case 0xd03f: return "Kodierungsfehler: Fehler im Parameterteil (z.B. Reservebytes ungleich NULL).";
|
||||
|
||||
case 0xd041: return "Datenfehler: Die Kennung der Statusliste ist unzulaessig.";
|
||||
case 0xd042: return "Datenfehler: Die Variablenadresse ist unzulaessig.";
|
||||
case 0xd044: return "Datenfehler: Der Variablenwert ist unzulaessig.Ueberpruefen Sie die Auftragsdaten.";
|
||||
case 0xd045: return "Datenfehler: Das Verlassen der ODIS-Steuerung bei HALT ist unzulaessig.";
|
||||
case 0xd046: return "Datenfehler: Die Messtufe bei Laufzeitmessung ist unzulaessig.";
|
||||
case 0xd047: return "Datenfehler: Die Hierarchie bei 'Auftragsliste lesen' ist unzulaessig.";
|
||||
case 0xd048: return "Datenfehler: Die Loeschkennung bei 'Auftrag loeschen' ist unzulaessig.";
|
||||
case 0xd049: return "Datenfehler: Die Ersetzkennung bei 'Auftrag ersetzen' ist unzulaessig.";
|
||||
case 0xd04a: return "Fehler bei der Ausfuehrung von 'Programmstatus'.";
|
||||
|
||||
case 0xd05f: return "Kodierungsfehler: Fehler im Datenteil (z.B. Reservebytes ungleich NULL,...).";
|
||||
|
||||
case 0xd061: return "Ressourcenfehler: Es ist kein Speicherplatz fuer den Auftrag vorhanden.";
|
||||
case 0xd062: return "Ressourcenfehler: Die Auftragsliste ist voll.";
|
||||
case 0xd063: return "Ressourcenfehler: Das Triggerereignis ist belegt.";
|
||||
case 0xd064: return "Ressourcenfehler: Der Speicherplatz fuer ein Element des Ereignispuffers ist zu klein.";
|
||||
case 0xd065: return "Ressourcenfehler: Der Speicherplatz fuer mehrere Elemente des Ereignispuffers ist zu klein.";
|
||||
case 0xd066: return "Ressourcenfehler: Der Timer fuer die Laufzeitmessung ist durch einen anderen Auftrag belegt.";
|
||||
case 0xd067: return "Ressourcenfehler: Es sind zu viele 'Steuern Variable'-Auftraege aktiv (insbesondere Mehrprozessorbetrieb).";
|
||||
|
||||
case 0xd081: return "Die Funktion ist im aktuellen Betriebszustand unzulaessig.";
|
||||
case 0xd082: return "Betriebszustandsfehler: Betriebszustand HALT kann nicht verlassen werden.";
|
||||
|
||||
case 0xd0a2: return "Funktion ist momentan nicht moeglich, da eine speicherveraendernde Funktion laeuft.";
|
||||
case 0xd0a3: return "Es sind zu viele 'Steuern Variable'-Auftraege auf die Peripherie aktiv (insbesondere Mehrprozessorbetrieb).";
|
||||
case 0xd0a4: return "'Forcen' ist schon eingerichtet.";
|
||||
case 0xd0a5: return "Der referenzierte Auftrag ist nicht vorhanden.";
|
||||
case 0xd0a6: return "Der Auftrag kann nicht gesperrt/freigegeben werden.";
|
||||
case 0xd0a7: return "Der Auftrag kann nicht geloescht werden, da dieser z.B. gerade gelesen wird. Versuchen Sie es spaeter noch einmal.";
|
||||
case 0xd0a8: return "Der Auftrag kann nicht ersetzt werden, da dieser z.B. gerade gelesen oder geloescht wird. Versuchen Sie es spaeter noch einmal.";
|
||||
case 0xd0a9: return "Der Auftrag kann nicht gelesen werden, da dieser z.B. gerade geloescht wird. Versuchen Sie es spaeter noch einmal.";
|
||||
case 0xd0aa: return "Das Zeitlimit im Prozessbetrieb ist ueberschritten.";
|
||||
case 0xd0ab: return "Die Auftragsparameter sind im Prozessbetrieb unzulaessig.";
|
||||
case 0xd0ac: return "Die Auftragsdaten sind im Prozessbetrieb unzulaessig.";
|
||||
case 0xd0ad: return "Der Betriebsmodus ist schon eingestellt.";
|
||||
case 0xd0ae: return "Der Auftrag wurde ueber eine andere Verbindung eingerichtet und kann nur ueber diese hantiert werden.";
|
||||
|
||||
case 0xd0c1: return "Beim Zugriff auf die Variable(n) wurde mindestens ein Fehler erkannt.";
|
||||
case 0xd0c2: return "Betriebszustandsuebergang in STOP/HALT.";
|
||||
case 0xd0c3: return "Beim Zugriff auf die Variable(n) wurde mindestens ein Fehler erkannt und Betriebszustandsuebergang in STOP/HALT.";
|
||||
case 0xd0c4: return "Timerueberlauf bei der die Laufzeitmessung";
|
||||
case 0xd0c5: return "Die Ausgabe des Bausteinstacks ist inkonsistent, da Bausteine geloescht/nachgeladen wurden.";
|
||||
case 0xd0c6: return "Der Auftrag wurde automatisch geloescht, weil alle in ihm referenzierten Auftraege geloescht wurden.";
|
||||
case 0xd0c7: return "Der Auftrag wurde automatisch geloescht, wegen Verlassens des Betriebszustands STOP.";
|
||||
case 0xd0c8: return "'Status Baustein' wurde abgebrochen wegen Inkonsistenz zwischen Testauftrag und Programm.";
|
||||
case 0xd0c9: return "Verlassen des Statusbereichs durch Ruecksetzen des OB90.";
|
||||
case 0xd0ca: return "Verlassen des Statusbereichs durch Ruecksetzen des OB90 und Zugriffsfehler beim Lesen der Variablen vor dem Verlassen.";
|
||||
case 0xd0cb: return "Die Ausgabesperre der Peripherie ist wieder eingeschaltet.";
|
||||
case 0xd0cc: return "Der Datenumfang fuer die Testfunktion ist durch das Zeitlimit eingeschraenkt.";
|
||||
|
||||
|
||||
case 0xd231: return "Mindestens ein geladener OB kann nicht kopiert werden, da die zugehoerige Ablaufebene nicht existiert.";
|
||||
case 0xd232: return "Mindestens eine Bausteinnummer eines geladenen Bausteins ist unzulaessig.";
|
||||
case 0xd234: return "Der Baustein ist im angegebenen Speichermedium oder im Auftrag doppelt vorhanden.";
|
||||
case 0xd235: return "Der Baustein enthaelt eine fehlerhafte Pruefsumme.";
|
||||
case 0xd236: return "Der Baustein enthaelt keine Pruefsumme.";
|
||||
case 0xd237: return "Der Baustein soll doppelt geladen werde, d.h. es existiert schon derselbe Baustein mit gleichem Zeitstempel auf der CPU.";
|
||||
case 0xd238: return "Mindestens ein angegebener Baustein ist kein DB.";
|
||||
case 0xd239: return "Mindestens ein angegebener DB ist nicht als eingekettete Variante im Ladespeicher vorhanden.";
|
||||
case 0xd23a: return "Mindestens ein angegebener DB hat wesentliche Unterschiede zwischen kopierter und eingeketteter Variante.";
|
||||
|
||||
case 0xd240: return "Die Koordinierungsregeln wurden verletzt.";
|
||||
case 0xd241: return "Die Funktion ist in der aktuellen Schutzstufe nicht erlaubt.";
|
||||
case 0xd242: return "Schutzverletzung bei der Bearbeitung von F-Bausteinen. F-Bausteine knnen nur nach Eingabe es Passwortes bearbeitet werden. Der F-Baustein SDB99 kann nicht geloescht werden.";
|
||||
|
||||
case 0xd250: return "Die Update- und Baugruppenkennung oder der Ausgabestand stimmen nicht ueberein.";
|
||||
case 0xd251: return "Falsche Reihenfolge der Betriebssystem-Komponenten.";
|
||||
case 0xd252: return "Pruefsummenfehler.";
|
||||
case 0xd253: return "Es ist kein ablauffaehiger Lader vorhanden; eine Aktualisierung ist nur ueber die Memory Card moeglich.";
|
||||
case 0xd254: return "Speicherfehler im Betriebssystem.";
|
||||
|
||||
case 0xd280: return "Fehler bei der Uebersetzung eines Bausteins in S7-300 CPU.";
|
||||
|
||||
case 0xd401: return "Auskunftsfunktion nicht verfuegbar.";
|
||||
case 0xd402: return "Auskunftsfunktion nicht verfuegbar.";
|
||||
case 0xd403: return "Der Dienst ist bereits angemeldet/abgemeldet (Diagnose/PMC).";
|
||||
case 0xd404: return "Die maximale Teilnehmerzahl wurde erreicht. Keine weitere Anmeldung fuer Diagnose/PMC moeglich.";
|
||||
case 0xd405: return "Der Dienst wird nicht unterstuetzt oder Syntaxfehler bei den Funktionsparametern.";
|
||||
case 0xd406: return "Die gewnschte Information ist temporaer nicht vorhanden.";
|
||||
case 0xd407: return "Es ist ein Diagnose-Fehler aufgetreten.";
|
||||
case 0xd408: return "Update abgebrochen.";
|
||||
case 0xd409: return "Am DP-Bus ist ein Fehler aufgetreten.";
|
||||
|
||||
|
||||
default: return daveStrerror(code);
|
||||
|
||||
}
|
||||
}
|
||||
2
nodaveext.h
Normal file
2
nodaveext.h
Normal file
@@ -0,0 +1,2 @@
|
||||
//#include "nodave.h"
|
||||
char * DECL2 daveStrerrorExt(int code);
|
||||
649
nodavesimple.h
Normal file
649
nodavesimple.h
Normal file
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
Part of Libnodave, a free communication libray for Siemens S7 200/300/400 via
|
||||
the MPI adapter 6ES7 972-0CA22-0XAC
|
||||
or MPI adapter 6ES7 972-0CA23-0XAC
|
||||
or TS adapter 6ES7 972-0CA33-0XAC
|
||||
or MPI adapter 6ES7 972-0CA11-0XAC,
|
||||
IBH/MHJ-NetLink or CPs 243, 343 and 443
|
||||
or VIPA Speed7 with builtin ethernet support.
|
||||
|
||||
(C) Thomas Hergenhahn (thomas.hergenhahn@web.de) 2002..2005
|
||||
|
||||
Libnodave is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Libnodave is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with Libnodave; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
Do NOT use this include file in C programs. It is just here for people who want
|
||||
to interface Libnodave with other programming languages, so they see that they
|
||||
do not neccessarily need to implement all the internal structures.
|
||||
|
||||
So if you plan to interface with other languages, this file shall show you
|
||||
show the minimum of structures and funtions you'll need to make known to your compiler.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __nodave
|
||||
#define __nodave
|
||||
|
||||
#ifdef LINUX
|
||||
#define DECL2
|
||||
#define EXPORTSPEC
|
||||
typedef struct {
|
||||
int rfd;
|
||||
int wfd;
|
||||
} _daveOSserialType;
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#ifdef BCCWIN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define DECL2 __stdcall
|
||||
//#define DECL2 cdecl
|
||||
#ifdef DOEXPORT
|
||||
#define EXPORTSPEC __declspec (dllexport)
|
||||
#else
|
||||
#define EXPORTSPEC __declspec (dllimport)
|
||||
#endif
|
||||
typedef struct {
|
||||
HANDLE rfd;
|
||||
HANDLE wfd;
|
||||
} _daveOSserialType;
|
||||
#else
|
||||
#error Fill in what you need for your OS or API.
|
||||
#endif /* BCCWIN */
|
||||
#endif /* LINUX */
|
||||
|
||||
/*
|
||||
Protocol types to be used with newInterface:
|
||||
*/
|
||||
#define daveProtoMPI 0 /* MPI for S7 300/400 */
|
||||
#define daveProtoMPI2 1 /* MPI for S7 300/400, "Andrew's version" */
|
||||
#define daveProtoMPI3 2 /* MPI for S7 300/400, Step 7 Version, not well tested */
|
||||
#define daveProtoMPI4 3 /* MPI for S7 300/400, "Andrew's version" with extra STX */
|
||||
#define daveProtoPPI 10 /* PPI for S7 200 */
|
||||
|
||||
#define daveProtoAS511 20 /* S5 programming port protocol */
|
||||
|
||||
#define daveProtoS7online 50 /* use s7onlinx.dll for transport */
|
||||
|
||||
#define daveProtoISOTCP 122 /* ISO over TCP */
|
||||
#define daveProtoISOTCP243 123 /* ISO over TCP with CP243 */
|
||||
|
||||
#define daveProtoNLpro 230 /* MPI with NetLink Pro MPI to ethernet gateway */
|
||||
|
||||
#define daveProtoMPI_IBH 223 /* MPI with IBH NetLink MPI to ethernet gateway */
|
||||
#define daveProtoPPI_IBH 224 /* PPI with IBH NetLink PPI to ethernet gateway */
|
||||
|
||||
#define daveProtoUserTransport 255 /* Libnodave will pass the PDUs of S7 Communication to user */
|
||||
/* defined call back functions. */
|
||||
|
||||
/*
|
||||
* ProfiBus speed constants:
|
||||
*/
|
||||
#define daveSpeed9k 0
|
||||
#define daveSpeed19k 1
|
||||
#define daveSpeed187k 2
|
||||
#define daveSpeed500k 3
|
||||
#define daveSpeed1500k 4
|
||||
#define daveSpeed45k 5
|
||||
#define daveSpeed93k 6
|
||||
|
||||
/*
|
||||
Some MPI function codes (yet unused ones may be incorrect).
|
||||
*/
|
||||
#define daveFuncOpenS7Connection 0xF0
|
||||
#define daveFuncRead 0x04
|
||||
#define daveFuncWrite 0x05
|
||||
#define daveFuncRequestDownload 0x1A
|
||||
#define daveFuncDownloadBlock 0x1B
|
||||
#define daveFuncDownloadEnded 0x1C
|
||||
#define daveFuncStartUpload 0x1D
|
||||
#define daveFuncUpload 0x1E
|
||||
#define daveFuncEndUpload 0x1F
|
||||
#define daveFuncInsertBlock 0x28
|
||||
/*
|
||||
S7 specific constants:
|
||||
*/
|
||||
#define daveBlockType_OB '8'
|
||||
#define daveBlockType_DB 'A'
|
||||
#define daveBlockType_SDB 'B'
|
||||
#define daveBlockType_FC 'C'
|
||||
#define daveBlockType_SFC 'D'
|
||||
#define daveBlockType_FB 'E'
|
||||
#define daveBlockType_SFB 'F'
|
||||
/*
|
||||
Use these constants for parameter "area" in daveReadBytes and daveWriteBytes
|
||||
*/
|
||||
#define daveSysInfo 0x3 /* System info of 200 family */
|
||||
#define daveSysFlags 0x5 /* System flags of 200 family */
|
||||
#define daveAnaIn 0x6 /* analog inputs of 200 family */
|
||||
#define daveAnaOut 0x7 /* analog outputs of 200 family */
|
||||
|
||||
#define daveP 0x80
|
||||
#define daveInputs 0x81
|
||||
#define daveOutputs 0x82
|
||||
#define daveFlags 0x83
|
||||
#define daveDB 0x84 /* data blocks */
|
||||
#define daveDI 0x85 /* instance data blocks */
|
||||
#define daveLocal 0x86 /* not tested */
|
||||
#define daveV 0x87 /* don't know what it is */
|
||||
#define daveCounter 28 /* S7 counters */
|
||||
#define daveTimer 29 /* S7 timers */
|
||||
#define daveCounter200 30 /* IEC counters (200 family) */
|
||||
#define daveTimer200 31 /* IEC timers (200 family) */
|
||||
|
||||
/**
|
||||
Library specific:
|
||||
**/
|
||||
/*
|
||||
Result codes. Genarally, 0 means ok,
|
||||
>0 are results (also errors) reported by the PLC
|
||||
<0 means error reported by library code.
|
||||
*/
|
||||
#define daveResOK 0 /* means all ok */
|
||||
#define daveResNoPeripheralAtAddress 1 /* CPU tells there is no peripheral at address */
|
||||
#define daveResMultipleBitsNotSupported 6 /* CPU tells it does not support to read a bit block with a */
|
||||
/* length other than 1 bit. */
|
||||
#define daveResItemNotAvailable200 3 /* means a a piece of data is not available in the CPU, e.g. */
|
||||
/* when trying to read a non existing DB or bit bloc of length<>1 */
|
||||
/* This code seems to be specific to 200 family. */
|
||||
|
||||
#define daveResItemNotAvailable 10 /* means a a piece of data is not available in the CPU, e.g. */
|
||||
/* when trying to read a non existing DB */
|
||||
|
||||
#define daveAddressOutOfRange 5 /* means the data address is beyond the CPUs address range */
|
||||
#define daveWriteDataSizeMismatch 7 /* means the write data size doesn't fit item size */
|
||||
#define daveResCannotEvaluatePDU -123
|
||||
#define daveResCPUNoData -124
|
||||
#define daveUnknownError -125
|
||||
#define daveEmptyResultError -126
|
||||
#define daveEmptyResultSetError -127
|
||||
#define daveResUnexpectedFunc -128
|
||||
#define daveResUnknownDataUnitSize -129
|
||||
|
||||
#define daveResShortPacket -1024
|
||||
#define daveResTimeout -1025
|
||||
|
||||
/*
|
||||
error code to message string conversion:
|
||||
Call this function to get an explanation for error codes returned by other functions.
|
||||
*/
|
||||
EXPORTSPEC char * DECL2 daveStrerror(int code);
|
||||
/*
|
||||
Copy an internal String into an external string buffer. This is needed to interface
|
||||
with Visual Basic. Maybe it is helpful elsewhere, too.
|
||||
*/
|
||||
EXPORTSPEC void DECL2 daveStringCopy(char * intString, char * extString);
|
||||
|
||||
/*
|
||||
Max number of bytes in a single message.
|
||||
*/
|
||||
#define daveMaxRawLen 2048
|
||||
/*
|
||||
Some definitions for debugging:
|
||||
*/
|
||||
#define daveDebugRawRead 0x01 /* Show the single bytes received */
|
||||
#define daveDebugSpecialChars 0x02 /* Show when special chars are read */
|
||||
#define daveDebugRawWrite 0x04 /* Show the single bytes written */
|
||||
#define daveDebugListReachables 0x08 /* Show the steps when determine devices in MPI net */
|
||||
#define daveDebugInitAdapter 0x10 /* Show the steps when Initilizing the MPI adapter */
|
||||
#define daveDebugConnect 0x20 /* Show the steps when connecting a PLC */
|
||||
#define daveDebugPacket 0x40
|
||||
#define daveDebugByte 0x80
|
||||
#define daveDebugCompare 0x100
|
||||
#define daveDebugExchange 0x200
|
||||
#define daveDebugPDU 0x400 /* debug PDU handling */
|
||||
#define daveDebugUpload 0x800 /* debug PDU loading program blocks from PLC */
|
||||
#define daveDebugMPI 0x1000
|
||||
#define daveDebugPrintErrors 0x2000 /* Print error messages */
|
||||
#define daveDebugPassive 0x4000
|
||||
#define daveDebugErrorReporting 0x8000
|
||||
#define daveDebugOpen 0x10000 /* print messages in openSocket and setPort */
|
||||
|
||||
#define daveDebugAll 0x1ffff
|
||||
/*
|
||||
set and read debug level:
|
||||
*/
|
||||
EXPORTSPEC void DECL2 daveSetDebug(int nDebug);
|
||||
EXPORTSPEC int DECL2 daveGetDebug(void);
|
||||
/*
|
||||
Some data types:
|
||||
*/
|
||||
#define uc unsigned char
|
||||
#define us unsigned short
|
||||
#define u32 unsigned int
|
||||
|
||||
/*
|
||||
This is a wrapper for the serial or ethernet interface. This is here to make porting easier.
|
||||
*/
|
||||
|
||||
typedef struct _daveConnection daveConnection;
|
||||
typedef struct _daveInterface daveInterface;
|
||||
|
||||
/*
|
||||
Helper struct to manage PDUs. This is NOT the part of the packet I would call PDU, but
|
||||
a set of pointers that ease access to the "private parts" of a PDU.
|
||||
*/
|
||||
/* While gcc-3.3 can handle a 0 size struct (at least pointers to it), BCC can't. */
|
||||
/*
|
||||
typedef struct {
|
||||
} PDU;
|
||||
*/
|
||||
typedef struct {
|
||||
uc * header; /* pointer to start of PDU (PDU header) */
|
||||
uc * param; /* pointer to start of parameters inside PDU */
|
||||
uc * data; /* pointer to start of data inside PDU */
|
||||
uc * udata; /* pointer to start of data inside PDU */
|
||||
int hlen; /* header length */
|
||||
int plen; /* parameter length */
|
||||
int dlen; /* data length */
|
||||
int udlen; /* user or result data length */
|
||||
} PDU;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
This groups an interface together with some information about it's properties
|
||||
in the library's context.
|
||||
*/
|
||||
struct _daveInterface {
|
||||
int _timeout; /* Timeout in microseconds used in transort. */
|
||||
};
|
||||
|
||||
EXPORTSPEC daveInterface * DECL2 daveNewInterface(_daveOSserialType nfd, char * nname, int localMPI, int protocol, int speed);
|
||||
|
||||
/*
|
||||
This holds data for a PLC connection;
|
||||
*/
|
||||
struct _daveConnection {
|
||||
int AnswLen; /* length of last message */
|
||||
uc * resultPointer; /* used to retrieve single values from the result byte array */
|
||||
int maxPDUlength;
|
||||
// int MPIAdr; /* The PLC's address */
|
||||
};
|
||||
|
||||
/*
|
||||
Setup a new connection structure using an initialized
|
||||
daveInterface and PLC's MPI address.
|
||||
*/
|
||||
EXPORTSPEC daveConnection * DECL2 daveNewConnection(daveInterface * di, int MPI,int rack, int slot);
|
||||
|
||||
typedef struct {
|
||||
uc type[2];
|
||||
unsigned short count;
|
||||
} daveBlockTypeEntry;
|
||||
|
||||
typedef struct {
|
||||
unsigned short number;
|
||||
uc type[2];
|
||||
} daveBlockEntry;
|
||||
/**
|
||||
PDU handling:
|
||||
PDU is the central structure present in S7 communication.
|
||||
It is composed of a 10 or 12 byte header,a parameter block and a data block.
|
||||
When reading or writing values, the data field is itself composed of a data
|
||||
header followed by payload data
|
||||
**/
|
||||
/*
|
||||
retrieve the answer
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveGetResponse(daveConnection * dc);
|
||||
/*
|
||||
send PDU to PLC
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveSendMessage(daveConnection * dc, PDU * p);
|
||||
|
||||
/******
|
||||
|
||||
Utilities:
|
||||
|
||||
****/
|
||||
/*
|
||||
Hex dump PDU:
|
||||
*/
|
||||
EXPORTSPEC void DECL2 _daveDumpPDU(PDU * p);
|
||||
|
||||
/*
|
||||
Hex dump. Write the name followed by len bytes written in hex and a newline:
|
||||
*/
|
||||
EXPORTSPEC void DECL2 _daveDump(char * name,uc*b,int len);
|
||||
|
||||
/*
|
||||
names for PLC objects:
|
||||
*/
|
||||
EXPORTSPEC char * DECL2 daveBlockName(uc bn);
|
||||
EXPORTSPEC char * DECL2 daveAreaName(uc n);
|
||||
|
||||
/*
|
||||
swap functions:
|
||||
*/
|
||||
EXPORTSPEC short DECL2 daveSwapIed_16(short ff);
|
||||
EXPORTSPEC int DECL2 daveSwapIed_32(int ff);
|
||||
|
||||
/**
|
||||
Data conversion convenience functions. The older set has been removed.
|
||||
Newer conversion routines. As the terms WORD, INT, INTEGER etc have different meanings
|
||||
for users of different programming languages and compilers, I choose to provide a new
|
||||
set of conversion routines named according to the bit length of the value used. The 'U'
|
||||
or 'S' stands for unsigned or signed.
|
||||
**/
|
||||
/*
|
||||
Get a value from the position b points to. B is typically a pointer to a buffer that has
|
||||
been filled with daveReadBytes:
|
||||
*/
|
||||
EXPORTSPEC float DECL2 daveGetFloatAt(daveConnection * dc, int pos);
|
||||
|
||||
|
||||
EXPORTSPEC float DECL2 toPLCfloat(float ff);
|
||||
EXPORTSPEC int DECL2 daveToPLCfloat(float ff);
|
||||
|
||||
|
||||
|
||||
EXPORTSPEC int DECL2 daveGetS8from(uc *b);
|
||||
EXPORTSPEC int DECL2 daveGetU8from(uc *b);
|
||||
EXPORTSPEC int DECL2 daveGetS16from(uc *b);
|
||||
EXPORTSPEC int DECL2 daveGetU16from(uc *b);
|
||||
EXPORTSPEC int DECL2 daveGetS32from(uc *b);
|
||||
EXPORTSPEC unsigned int DECL2 daveGetU32from(uc *b);
|
||||
EXPORTSPEC float DECL2 daveGetFloatfrom(uc *b);
|
||||
/*
|
||||
Get a value from the current position in the last result read on the connection dc.
|
||||
This will increment an internal pointer, so the next value is read from the position
|
||||
following this value.
|
||||
*/
|
||||
|
||||
EXPORTSPEC int DECL2 daveGetS8(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveGetU8(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveGetS16(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveGetU16(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveGetS32(daveConnection * dc);
|
||||
EXPORTSPEC unsigned int DECL2 daveGetU32(daveConnection * dc);
|
||||
EXPORTSPEC float DECL2 daveGetFloat(daveConnection * dc);
|
||||
/*
|
||||
Get a value from a given position in the last result read on the connection dc.
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveGetS8At(daveConnection * dc, int pos);
|
||||
EXPORTSPEC int DECL2 daveGetU8At(daveConnection * dc, int pos);
|
||||
EXPORTSPEC int DECL2 daveGetS16At(daveConnection * dc, int pos);
|
||||
EXPORTSPEC int DECL2 daveGetU16At(daveConnection * dc, int pos);
|
||||
EXPORTSPEC int DECL2 daveGetS32At(daveConnection * dc, int pos);
|
||||
EXPORTSPEC unsigned int DECL2 daveGetU32At(daveConnection * dc, int pos);
|
||||
/*
|
||||
put one byte into buffer b:
|
||||
*/
|
||||
EXPORTSPEC uc * DECL2 davePut8(uc *b,int v);
|
||||
EXPORTSPEC uc * DECL2 davePut16(uc *b,int v);
|
||||
EXPORTSPEC uc * DECL2 davePut32(uc *b,int v);
|
||||
EXPORTSPEC uc * DECL2 davePutFloat(uc *b,float v);
|
||||
|
||||
EXPORTSPEC void DECL2 davePut8At(uc *b, int pos, int v);
|
||||
EXPORTSPEC void DECL2 davePut16At(uc *b, int pos, int v);
|
||||
EXPORTSPEC void DECL2 davePut32At(uc *b, int pos, int v);
|
||||
EXPORTSPEC void DECL2 davePutFloatAt(uc *b,int pos, float v);
|
||||
/**
|
||||
Timer and Counter conversion functions:
|
||||
**/
|
||||
/*
|
||||
get time in seconds from current read position:
|
||||
*/
|
||||
EXPORTSPEC float DECL2 daveGetSeconds(daveConnection * dc);
|
||||
/*
|
||||
get time in seconds from random position:
|
||||
*/
|
||||
EXPORTSPEC float DECL2 daveGetSecondsAt(daveConnection * dc, int pos);
|
||||
/*
|
||||
get counter value from current read position:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveGetCounterValue(daveConnection * dc);
|
||||
/*
|
||||
get counter value from random read position:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveGetCounterValueAt(daveConnection * dc,int pos);
|
||||
|
||||
/*
|
||||
Functions to load blocks from PLC:
|
||||
*/
|
||||
EXPORTSPEC void DECL2 _daveConstructUpload(PDU *p,char blockType, int blockNr);
|
||||
|
||||
EXPORTSPEC void DECL2 _daveConstructDoUpload(PDU * p, int uploadID);
|
||||
|
||||
EXPORTSPEC void DECL2 _daveConstructEndUpload(PDU * p, int uploadID);
|
||||
/*
|
||||
Get the PLC's order code as ASCIIZ. Buf must provide space for
|
||||
21 characters at least.
|
||||
*/
|
||||
|
||||
#define daveOrderCodeSize 21
|
||||
EXPORTSPEC int DECL2 daveGetOrderCode(daveConnection * dc,char * buf);
|
||||
/*
|
||||
connect to a PLC. returns 0 on success.
|
||||
*/
|
||||
|
||||
EXPORTSPEC int DECL2 daveConnectPLC(daveConnection * dc);
|
||||
|
||||
/*
|
||||
Read len bytes from the PLC. Start determines the first byte.
|
||||
Area denotes whether the data comes from FLAGS, DATA BLOCKS,
|
||||
INPUTS or OUTPUTS, etc.
|
||||
DB is the number of the data block to be used. Set it to zero
|
||||
for other area types.
|
||||
Buffer is a pointer to a memory block provided by the calling
|
||||
program. If the pointer is not NULL, the result data will be copied thereto.
|
||||
Hence it must be big enough to take up the result.
|
||||
In any case, you can also retrieve the result data using the get<type> macros
|
||||
on the connection pointer.
|
||||
|
||||
RESTRICTION:There is no check for max. message len or automatic splitting into
|
||||
multiple messages. Use daveReadManyBytes() in case the data you want
|
||||
to read doesn't fit into a single PDU.
|
||||
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveReadBytes(daveConnection * dc, int area, int DB, int start, int len, void * buffer);
|
||||
|
||||
/*
|
||||
Read len bytes from the PLC. Start determines the first byte.
|
||||
In contrast to daveReadBytes(), this function can read blocks
|
||||
that are too long for a single transaction. To achieve this,
|
||||
the data is fetched with multiple subsequent read requests to
|
||||
the CPU.
|
||||
Area denotes whether the data comes from FLAGS, DATA BLOCKS,
|
||||
INPUTS or OUTPUTS, etc.
|
||||
DB is the number of the data block to be used. Set it to zero
|
||||
for other area types.
|
||||
Buffer is a pointer to a memory block provided by the calling
|
||||
program. It may not be NULL, the result data will be copied thereto.
|
||||
Hence it must be big enough to take up the result.
|
||||
You CANNOT read result bytes from the internal buffer of the
|
||||
daveConnection. This buffer is overwritten in each read request.
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveReadManyBytes(daveConnection * dc,int area, int DBnum, int start,int len, void * buffer);
|
||||
|
||||
/*
|
||||
Write len bytes from buffer to the PLC.
|
||||
Start determines the first byte.
|
||||
Area denotes whether the data goes to FLAGS, DATA BLOCKS,
|
||||
INPUTS or OUTPUTS, etc.
|
||||
DB is the number of the data block to be used. Set it to zero
|
||||
for other area types.
|
||||
RESTRICTION: There is no check for max. message len or automatic splitting into
|
||||
multiple messages. Use daveReadManyBytes() in case the data you want
|
||||
to read doesn't fit into a single PDU.
|
||||
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveWriteBytes(daveConnection * dc,int area, int DB, int start, int len, void * buffer);
|
||||
|
||||
/*
|
||||
Write len bytes to the PLC. Start determines the first byte.
|
||||
In contrast to daveWriteBytes(), this function can write blocks
|
||||
that are too long for a single transaction. To achieve this, the
|
||||
the data is transported with multiple subsequent write requests to
|
||||
the CPU.
|
||||
Area denotes whether the data comes from FLAGS, DATA BLOCKS,
|
||||
INPUTS or OUTPUTS, etc.
|
||||
DB is the number of the data block to be used. Set it to zero
|
||||
for other area types.
|
||||
Buffer is a pointer to a memory block provided by the calling
|
||||
program. It may not be NULL.
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveWriteManyBytes(daveConnection * dc,int area, int DB, int start, int len, void * buffer);
|
||||
|
||||
/*
|
||||
Bit manipulation:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveReadBits(daveConnection * dc, int area, int DB, int start, int len, void * buffer);
|
||||
EXPORTSPEC int DECL2 daveWriteBits(daveConnection * dc,int area, int DB, int start, int len, void * buffer);
|
||||
EXPORTSPEC int DECL2 daveSetBit(daveConnection * dc,int area, int DB, int byteAdr, int bitAdr);
|
||||
EXPORTSPEC int DECL2 daveClrBit(daveConnection * dc,int area, int DB, int byteAdr, int bitAdr);
|
||||
|
||||
/*
|
||||
PLC diagnostic and inventory functions:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveReadSZL(daveConnection * dc, int ID, int index, void * buf, int buflen);
|
||||
EXPORTSPEC int DECL2 daveListBlocksOfType(daveConnection * dc,uc type,daveBlockEntry * buf);
|
||||
EXPORTSPEC int DECL2 daveListBlocks(daveConnection * dc,daveBlockTypeEntry * buf);
|
||||
/*
|
||||
PLC program read functions:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 initUpload(daveConnection * dc,char blockType, int blockNr, int * uploadID);
|
||||
EXPORTSPEC int DECL2 doUpload(daveConnection*dc, int * more, uc**buffer, int*len, int uploadID);
|
||||
EXPORTSPEC int DECL2 endUpload(daveConnection*dc, int uploadID);
|
||||
EXPORTSPEC int DECL2 daveGetProgramBlock(daveConnection * dc, int blockType, int number, char* buffer, int * length);
|
||||
/*
|
||||
PLC run/stop control functions:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveStop(daveConnection*dc);
|
||||
EXPORTSPEC int DECL2 daveStart(daveConnection*dc);
|
||||
/*
|
||||
PLC special commands
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveCopyRAMtoROM(daveConnection*dc);
|
||||
|
||||
EXPORTSPEC int DECL2 daveForce200(daveConnection * dc, int area, int start, int val);
|
||||
/*
|
||||
Multiple variable support:
|
||||
*/
|
||||
typedef struct {
|
||||
int error;
|
||||
int length;
|
||||
uc * bytes;
|
||||
} daveResult;
|
||||
|
||||
typedef struct {
|
||||
int numResults;
|
||||
daveResult * results;
|
||||
} daveResultSet;
|
||||
|
||||
|
||||
/* use this to initialize a multivariable read: */
|
||||
EXPORTSPEC void DECL2 davePrepareReadRequest(daveConnection * dc, PDU *p);
|
||||
/* Adds a new variable to a prepared request: */
|
||||
EXPORTSPEC void DECL2 daveAddVarToReadRequest(PDU *p, int area, int DBnum, int start, int bytes);
|
||||
/* Executes the complete request. */
|
||||
EXPORTSPEC int DECL2 daveExecReadRequest(daveConnection * dc, PDU *p, daveResultSet * rl);
|
||||
/* Lets the functions daveGet<data type> work on the n-th result: */
|
||||
EXPORTSPEC int DECL2 daveUseResult(daveConnection * dc, daveResultSet * rl, int n);
|
||||
/* Frees the memory occupied by the result structure */
|
||||
EXPORTSPEC void DECL2 daveFreeResults(daveResultSet * rl);
|
||||
/* Adds a new bit variable to a prepared request: */
|
||||
EXPORTSPEC void DECL2 daveAddBitVarToReadRequest(PDU *p, int area, int DBnum, int start, int byteCount);
|
||||
|
||||
/* use this to initialize a multivariable write: */
|
||||
EXPORTSPEC void DECL2 davePrepareWriteRequest(daveConnection * dc, PDU *p);
|
||||
/* Adds a new variable to a prepared request: */
|
||||
EXPORTSPEC void DECL2 daveAddVarToWriteRequest(PDU *p, int area, int DBnum, int start, int bytes, void * buffer);
|
||||
/* Adds a new bit variable to a prepared write request: */
|
||||
EXPORTSPEC void DECL2 daveAddBitVarToWriteRequest(PDU *p, int area, int DBnum, int start, int byteCount, void * buffer);
|
||||
/* Executes the complete request. */
|
||||
EXPORTSPEC int DECL2 daveExecWriteRequest(daveConnection * dc, PDU *p, daveResultSet * rl);
|
||||
|
||||
|
||||
EXPORTSPEC int DECL2 daveInitAdapter(daveInterface * di);
|
||||
EXPORTSPEC int DECL2 daveConnectPLC(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveDisconnectPLC(daveConnection * dc);
|
||||
|
||||
EXPORTSPEC int DECL2 daveDisconnectAdapter(daveInterface * di);
|
||||
EXPORTSPEC int DECL2 daveListReachablePartners(daveInterface * di,char * buf);
|
||||
|
||||
/* MPI specific functions */
|
||||
|
||||
#define daveMPIReachable 0x30
|
||||
#define daveMPIActive 0x30
|
||||
#define daveMPIPassive 0x00
|
||||
#define daveMPIunused 0x10
|
||||
#define davePartnerListSize 126
|
||||
/**
|
||||
C# interoperability:
|
||||
**/
|
||||
EXPORTSPEC void DECL2 daveSetTimeout(daveInterface * di, int tmo);
|
||||
EXPORTSPEC int DECL2 daveGetTimeout(daveInterface * di);
|
||||
|
||||
EXPORTSPEC char * DECL2 daveGetName(daveInterface * di);
|
||||
|
||||
EXPORTSPEC int DECL2 daveGetMPIAdr(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveGetAnswLen(daveConnection * dc);
|
||||
EXPORTSPEC int DECL2 daveGetMaxPDULen(daveConnection * dc);
|
||||
EXPORTSPEC daveResultSet * DECL2 daveNewResultSet();
|
||||
EXPORTSPEC void DECL2 daveFree(void * dc);
|
||||
EXPORTSPEC PDU * DECL2 daveNewPDU();
|
||||
EXPORTSPEC int DECL2 daveGetErrorOfResult(daveResultSet *,int number);
|
||||
|
||||
/*
|
||||
Special function do disconnect arbitrary connections on IBH-Link:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveForceDisconnectIBH(daveInterface * di, int src, int dest, int mpi);
|
||||
/*
|
||||
Special function do reset an IBH-Link:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveResetIBH(daveInterface * di);
|
||||
/**
|
||||
Program Block from PLC:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveGetProgramBlock(daveConnection * dc, int blockType, int number, char* buffer, int * length);
|
||||
/**
|
||||
PLC realtime clock handling:
|
||||
*/
|
||||
/*
|
||||
read out clock:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveReadPLCTime(daveConnection * dc);
|
||||
/*
|
||||
set clock to a value given by user:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveSetPLCTime(daveConnection * dc,uc * ts);
|
||||
/*
|
||||
set clock to PC system clock:
|
||||
*/
|
||||
EXPORTSPEC int DECL2 daveSetPLCTimeToSystime(daveConnection * dc);
|
||||
|
||||
EXPORTSPEC uc DECL2 daveToBCD(uc i);
|
||||
EXPORTSPEC uc DECL2 daveFromBCD(uc i);
|
||||
|
||||
#endif /* _nodave */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Changes:
|
||||
04/10/05 first version.
|
||||
09/11/05 added read/write functions for long blocks of data.
|
||||
10/26/07 fixed __cplusplus
|
||||
*/
|
||||
70
openS7online.c
Normal file
70
openS7online.c
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
#include "openS7online.h"
|
||||
#include "log2.h"
|
||||
#ifdef BCCWIN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Access S7onlinx.dll and load pointers to the functions.
|
||||
We load them using GetProcAddress on their names because:
|
||||
1. We have no .lib file for them.
|
||||
2. We don't want to link with a particular version.
|
||||
3. Libnodave shall remain useable without Siemens .dlls. So it shall not try to access them
|
||||
unless the user chooses the daveProtoS7online.
|
||||
*/
|
||||
|
||||
extern int daveDebug;
|
||||
|
||||
typedef int (DECL2 * _setHWnd) (int, HWND);
|
||||
|
||||
EXPORTSPEC HANDLE DECL2 openS7online(const char * accessPoint, HWND handle) {
|
||||
HMODULE hmod;
|
||||
int h,en;
|
||||
_setHWnd SetSinecHWnd;
|
||||
|
||||
hmod=LoadLibrary("S7onlinx.dll");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("LoadLibrary(S7onlinx.dll) returned %p)\n",hmod);
|
||||
|
||||
SCP_open=GetProcAddress(hmod,"SCP_open");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("GetProcAddress returned %p)\n",SCP_open);
|
||||
|
||||
SCP_close=GetProcAddress(hmod,"SCP_close");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("GetProcAddress returned %p)\n",SCP_close);
|
||||
|
||||
SCP_get_errno=GetProcAddress(hmod,"SCP_get_errno");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("GetProcAddress returned %p)\n",SCP_get_errno);
|
||||
|
||||
SCP_send=GetProcAddress(hmod,"SCP_send");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("GetProcAddress returned %p)\n",SCP_send);
|
||||
|
||||
SCP_receive=GetProcAddress(hmod,"SCP_receive");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("GetProcAddress returned %p)\n",SCP_receive);
|
||||
|
||||
SetSinecHWnd=GetProcAddress(hmod,"SetSinecHWnd");
|
||||
if (daveDebug & daveDebugOpen)
|
||||
LOG2("GetProcAddress returned %p)\n",SetSinecHWnd);
|
||||
|
||||
en=SCP_get_errno();
|
||||
h=SCP_open(accessPoint);
|
||||
en=SCP_get_errno();
|
||||
LOG3("handle: %d error:%d\n", h, en);
|
||||
SetSinecHWnd(h, handle);
|
||||
return h;
|
||||
};
|
||||
|
||||
EXPORTSPEC HANDLE DECL2 closeS7online(int h) {
|
||||
SCP_close(h);
|
||||
}
|
||||
|
||||
/*
|
||||
01/09/07 Used Axel Kinting's version.
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user