9 Commits

4 changed files with 46 additions and 38 deletions

View File

@ -5,7 +5,3 @@ BUILDCLASSES+=Linux
DBDS += s7plcFWBase.dbd DBDS += s7plcFWBase.dbd
DBDS_3.14 += s7plcFWCalcout.dbd DBDS_3.14 += s7plcFWCalcout.dbd
DBDS_3.14 += s7plcFWReg.dbd DBDS_3.14 += s7plcFWReg.dbd
EPICS_VERSIONS =
EPICS_VERSIONS += 3.14.8
EPICS_VERSIONS += 3.14.12

View File

@ -34,15 +34,14 @@
#include <stringoutRecord.h> #include <stringoutRecord.h>
#include <waveformRecord.h> #include <waveformRecord.h>
#if ((EPICS_VERSION==3 && EPICS_REVISION>=14) || EPICS_VERSION>3) #ifdef BASE_VERSION
/* R3.14 */ #define EPICS_3_13
#include "compat3_13.h"
#else
#include <postfix.h> #include <postfix.h>
#include <calcoutRecord.h> #include <calcoutRecord.h>
#include <cantProceed.h> #include <cantProceed.h>
#include <epicsExport.h> #include <epicsExport.h>
#else
/* R3.13 */
#include "compat3_13.h"
#endif #endif
/* suppress compiler warning concerning long long with __extension__ */ /* suppress compiler warning concerning long long with __extension__ */
@ -361,7 +360,7 @@ struct devsup s7plcFWWaveform =
epicsExportAddress(dset, s7plcFWWaveform); epicsExportAddress(dset, s7plcFWWaveform);
/* calcout **********************************************************/ /* calcout **********************************************************/
#if ((EPICS_VERSION==3 && EPICS_REVISION>=14) || EPICS_VERSION>3) #ifndef EPICS_3_13
STATIC long s7plcFWInitRecordCalcout(calcoutRecord *); STATIC long s7plcFWInitRecordCalcout(calcoutRecord *);
STATIC long s7plcFWWriteCalcout(calcoutRecord *); STATIC long s7plcFWWriteCalcout(calcoutRecord *);
@ -1761,7 +1760,7 @@ STATIC long s7plcFWReadAi(aiRecord *record)
case epicsFloat64T: case epicsFloat64T:
status = s7plcFWRead(priv->station, priv->offs, status = s7plcFWRead(priv->station, priv->offs,
8, &val64); 8, &val64);
__extension__ s7plcFWDebugLog(3, "ai %s: read 64bit %08Lx = %g\n", __extension__ s7plcFWDebugLog(3, "ai %s: read 64bit " CONV64 " = %g\n",
record->name, val64.i, val64.f); record->name, val64.i, val64.f);
floatval = TRUE; floatval = TRUE;
break; break;
@ -2025,7 +2024,7 @@ STATIC long s7plcFWInitRecordStringin(stringinRecord *record)
{ {
errlogSevPrintf(errlogMinor, errlogSevPrintf(errlogMinor,
"%s: string size reduced from %d to %d\n", "%s: string size reduced from %d to %d\n",
record->name, priv->dlen, sizeof(record->val)); record->name, priv->dlen, (int)sizeof(record->val));
priv->dlen = sizeof(record->val); priv->dlen = sizeof(record->val);
} }
record->dpvt = priv; record->dpvt = priv;
@ -2105,7 +2104,7 @@ STATIC long s7plcFWInitRecordStringout(stringoutRecord *record)
{ {
errlogSevPrintf(errlogMinor, errlogSevPrintf(errlogMinor,
"%s: string size reduced from %d to %d\n", "%s: string size reduced from %d to %d\n",
record->name, priv->dlen, sizeof(record->val)); record->name, priv->dlen, (int)sizeof(record->val));
priv->dlen = sizeof(record->val); priv->dlen = sizeof(record->val);
} }
record->dpvt = priv; record->dpvt = priv;
@ -2368,8 +2367,8 @@ STATIC long s7plcFWReadWaveform(waveformRecord *record)
return status; return status;
} }
#if (EPICS_REVISION>=14)
/* calcout **********************************************************/ /* calcout **********************************************************/
#ifndef EPICS_3_13
STATIC long s7plcFWInitRecordCalcout(calcoutRecord *record) STATIC long s7plcFWInitRecordCalcout(calcoutRecord *record)
{ {

View File

@ -1,7 +1,7 @@
/* $Date: 2012/03/06 10:53:08 $ */ /* $Date: 2013/07/11 12:43:21 $ */
/* $Id: drvS7plcFW.c,v 1.2 2012/03/06 10:53:08 anicic Exp $ */ /* $Id: drvS7plcFW.c,v 1.6 2013/07/11 12:43:21 anicic Exp $ */
/* $Name: $ */ /* $Name: $ */
/* $Revision: 1.2 $ */ /* $Revision: 1.6 $ */
/* /*
* NOTE: s7plcFWwriteThread -is not used for writting (we write direct), * NOTE: s7plcFWwriteThread -is not used for writting (we write direct),
@ -63,12 +63,13 @@
#include <endian.h> #include <endian.h>
#endif #endif
#define STACK_SIZE 20000 /* io thread stack size */ /* #define STACK_SIZE 20000 */ /* io thread stack size */
#define STACK_SIZE epicsThreadGetStackSize(epicsThreadStackBig)
#define CONNECT_TIMEOUT 5.0 /* connect timeout [s] */ #define CONNECT_TIMEOUT 5.0 /* connect timeout [s] */
#define RECONNECT_DELAY 10.0 /* delay before reconnect [s] */ #define RECONNECT_DELAY 10.0 /* delay before reconnect [s] */
static char cvsid[] __attribute__((unused)) = static char cvsid[] __attribute__((unused)) =
"$Id: drvS7plcFW.c,v 1.2 2012/03/06 10:53:08 anicic Exp $"; "$Id: drvS7plcFW.c,v 1.6 2013/07/11 12:43:21 anicic Exp $";
STATIC long s7plcFWIoReport(int level); STATIC long s7plcFWIoReport(int level);
STATIC long s7plcFWInit(); STATIC long s7plcFWInit();
@ -135,6 +136,8 @@ struct s7plcFWStation {
char *fetchBuffer, *writeBuffer; char *fetchBuffer, *writeBuffer;
int swapBytes; int swapBytes;
float recvTimeout, recvDelay, outIOintDelay; float recvTimeout, recvDelay, outIOintDelay;
int writeAll; // flag, when != 0 then always write the whole buffer to DB (needed for SINQ)
}; };
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@ -170,8 +173,8 @@ STATIC long s7plcFWIoReport(int level)
printf(" NOT CONNECTED\n"); printf(" NOT CONNECTED\n");
} }
printf(" WRITE: Port=%5d Org=%3d Db=%3d Offs=%5d Size=%5d buffer@%p (%5d bytes)", printf(" WRITE: Port=%5d Org=%3d Db=%3d Offs=%5d Size=%5d buffer@%p (%5d bytes) %s",
station->writePort, station->writeOrg, station->writeDb, station->writeOffs, station->writeSize, station->writeBuffer, station->writeSize); station->writePort, station->writeOrg, station->writeDb, station->writeOffs, station->writeSize, station->writeBuffer, station->writeSize, (station->writeAll ? "" : "writeAll"));
if (station->writeConnStatus) { if (station->writeConnStatus) {
printf(" CONNECTED (fd=%d)\n", station->writeSocket); printf(" CONNECTED (fd=%d)\n", station->writeSocket);
} }
@ -186,9 +189,9 @@ STATIC long s7plcFWIoReport(int level)
"ioc:motorola <-> plc:intel" : "no (both motorola)" "ioc:motorola <-> plc:intel" : "no (both motorola)"
#endif #endif
); );
printf(" receive timeout %g sec\n", station->recvTimeout); printf(" receive timeout %d ms\n", (int)(station->recvTimeout * 1000.0));
printf(" receive delay %g sec\n", station->recvDelay); printf(" receive delay %d ms\n", (int)(station->recvDelay * 1000.0));
printf(" outIOint delay %g sec\n", station->outIOintDelay); printf(" outIOint delay %d ms\n", (int)(station->outIOintDelay * 1000.0));
} }
} }
return 0; return 0;
@ -247,6 +250,7 @@ int s7plcFWConfigure(char *name, char* IPaddr, char *fetchInfo, char *writeInfo,
unsigned char fetchDb, writeDb; unsigned char fetchDb, writeDb;
unsigned int fetchOffs, writeOffs; unsigned int fetchOffs, writeOffs;
unsigned int fetchSize, writeSize; unsigned int fetchSize, writeSize;
int writeAll;
if (!name) { if (!name) {
errlogSevPrintf(errlogFatal, "s7plcFWConfigure: missing name\n"); errlogSevPrintf(errlogFatal, "s7plcFWConfigure: missing name\n");
@ -267,6 +271,7 @@ int s7plcFWConfigure(char *name, char* IPaddr, char *fetchInfo, char *writeInfo,
extractPGDOS(fetchInfo, &fetchPort, &fetchOrg, &fetchDb, &fetchOffs, &fetchSize); extractPGDOS(fetchInfo, &fetchPort, &fetchOrg, &fetchDb, &fetchOffs, &fetchSize);
extractPGDOS(writeInfo, &writePort, &writeOrg, &writeDb, &writeOffs, &writeSize); extractPGDOS(writeInfo, &writePort, &writeOrg, &writeDb, &writeOffs, &writeSize);
writeAll = 0; if (strstr(writeInfo, "writeall") != NULL) writeAll = 1; // write the whole buffer to DB
if ((fetchPort == 0) || (fetchOrg == 0) || (fetchDb == 0) || ((fetchOffs%2) != 0) || (fetchSize == 0) || ((fetchSize%2) != 0)) { /* size & offs: only even numbers */ if ((fetchPort == 0) || (fetchOrg == 0) || (fetchDb == 0) || ((fetchOffs%2) != 0) || (fetchSize == 0) || ((fetchSize%2) != 0)) { /* size & offs: only even numbers */
fetchPort = fetchOrg = fetchDb = fetchOffs = fetchSize = 0; fetchPort = fetchOrg = fetchDb = fetchOffs = fetchSize = 0;
@ -308,6 +313,7 @@ int s7plcFWConfigure(char *name, char* IPaddr, char *fetchInfo, char *writeInfo,
station->writeOffs = writeOffs; station->writeOffs = writeOffs;
station->fetchSize = fetchSize; station->fetchSize = fetchSize;
station->writeSize = writeSize; station->writeSize = writeSize;
station->writeAll = writeAll;
if (fetchSize > 0) if (fetchSize > 0)
station->fetchBuffer = callocMustSucceed(1, fetchSize, "s7plcFWConfigure"); station->fetchBuffer = callocMustSucceed(1, fetchSize, "s7plcFWConfigure");
@ -388,11 +394,9 @@ static const iocshArg * const s7plcFWConfigureArgs[] = {
static const iocshFuncDef s7plcFWConfigureDef = { "s7plcFWConfigure", 8, s7plcFWConfigureArgs }; static const iocshFuncDef s7plcFWConfigureDef = { "s7plcFWConfigure", 8, s7plcFWConfigureArgs };
static void s7plcFWConfigureFunc (const iocshArgBuf *args) static void s7plcFWConfigureFunc (const iocshArgBuf *args)
{ {
int status = s7plcFWConfigure( (void) s7plcFWConfigure(
args[0].sval, args[1].sval, args[2].sval, args[3].sval, args[0].sval, args[1].sval, args[2].sval, args[3].sval,
args[4].ival, args[5].ival, args[6].ival, args[7].ival); args[4].ival, args[5].ival, args[6].ival, args[7].ival);
if (status) exit(1);
} }
static void s7plcFWRegister () static void s7plcFWRegister ()
@ -452,8 +456,8 @@ STATIC void s7plcFWMain ()
} }
s7plcFWDebugLog(1, "s7plcFWMain %s: Connect to %s:%d on fetch socket %d\n", station->name, station->serverIP, station->fetchPort, station->fetchSocket); s7plcFWDebugLog(1, "s7plcFWMain %s: Connect to %s:%d on fetch socket %d\n", station->name, station->serverIP, station->fetchPort, station->fetchSocket);
if (s7plcFWEstablishConnection(station, FOR_FETCH) < 0) { if (s7plcFWEstablishConnection(station, FOR_FETCH) < 0) {
s7plcFWDebugLog(1, "s7plcFWMain %s: connect(%d, %s:%d) failed for fetch: %s. Retry in %g seconds\n", s7plcFWDebugLog(1, "s7plcFWMain %s: connect(%d, %s:%d) failed for fetch: %s. Retry in %d ms\n",
station->name, station->fetchSocket, station->serverIP, station->fetchPort, strerror(errno), (double)RECONNECT_DELAY); station->name, station->fetchSocket, station->serverIP, station->fetchPort, strerror(errno), (int)(RECONNECT_DELAY * 1000.0));
if (close(station->fetchSocket) && errno != ENOTCONN) { if (close(station->fetchSocket) && errno != ENOTCONN) {
s7plcFWDebugLog(1, "s7plcFWMain %s: close(%d) failed for fetch (ignored): %s\n", station->name, station->fetchSocket, strerror(errno)); s7plcFWDebugLog(1, "s7plcFWMain %s: close(%d) failed for fetch (ignored): %s\n", station->name, station->fetchSocket, strerror(errno));
} }
@ -476,8 +480,8 @@ STATIC void s7plcFWMain ()
} }
s7plcFWDebugLog(1, "s7plcFWMain %s: Connect to %s:%d on write socket %d\n", station->name, station->serverIP, station->writePort, station->writeSocket); s7plcFWDebugLog(1, "s7plcFWMain %s: Connect to %s:%d on write socket %d\n", station->name, station->serverIP, station->writePort, station->writeSocket);
if (s7plcFWEstablishConnection(station, FOR_WRITE) < 0) { if (s7plcFWEstablishConnection(station, FOR_WRITE) < 0) {
s7plcFWDebugLog(1, "s7plcFWMain %s: connect(%d, %s:%d) failed for write: %s. Retry in %g seconds\n", s7plcFWDebugLog(1, "s7plcFWMain %s: connect(%d, %s:%d) failed for write: %s. Retry in %d ms\n",
station->name, station->writeSocket, station->serverIP, station->writePort, strerror(errno), (double)RECONNECT_DELAY); station->name, station->writeSocket, station->serverIP, station->writePort, strerror(errno), (int)(RECONNECT_DELAY * 1000.0));
if (close(station->writeSocket) && errno != ENOTCONN) { if (close(station->writeSocket) && errno != ENOTCONN) {
s7plcFWDebugLog(1, "s7plcFWMain %s: close(%d) failed for write (ignored): %s\n", station->name, station->writeSocket, strerror(errno)); s7plcFWDebugLog(1, "s7plcFWMain %s: close(%d) failed for write (ignored): %s\n", station->name, station->writeSocket, strerror(errno));
} }
@ -659,7 +663,7 @@ STATIC int s7plcFWdoFetch(s7plcFWStation *station, int org, int db, int offs, in
input = 0; input = 0;
while (input < size) { while (input < size) {
s7plcFWDebugLog(3, "s7plcFWdoFetch: %s: waiting for input for %g seconds\n", station->name, station->recvTimeout); s7plcFWDebugLog(3, "s7plcFWdoFetch: %s: waiting for input for %d ms\n", station->name, (int)(station->recvTimeout * 1000.0));
status = s7plcFWWaitForInput(station, FOR_FETCH, station->recvTimeout); status = s7plcFWWaitForInput(station, FOR_FETCH, station->recvTimeout);
if (status <= 0) { if (status <= 0) {
s7plcFWDebugLog(0, "s7plcFWdoFetch: %s: s7plcFWWaitForInput(%d, ..., %d, 0) failed\n", station->name, station->fetchSocket, size - input); s7plcFWDebugLog(0, "s7plcFWdoFetch: %s: s7plcFWWaitForInput(%d, ..., %d, 0) failed\n", station->name, station->fetchSocket, size - input);
@ -811,7 +815,12 @@ int s7plcFWWriteMaskedArray(s7plcFWStation *station, unsigned int offset, unsign
/* warning: we allways have to write even number of bytes - so it can happen that we have to write 1 or 2 bytes more than requested */ /* warning: we allways have to write even number of bytes - so it can happen that we have to write 1 or 2 bytes more than requested */
woffs = offset & 0xFFFFFFFE; /* we need even byte offset */ woffs = offset & 0xFFFFFFFE; /* we need even byte offset */
wlen = 0; if (woffs != offset) wlen += 1; wlen += nelem*dlen; if ((wlen % 2) != 0) wlen += 1; wlen = 0; if (woffs != offset) wlen += 1; wlen += nelem*dlen; if ((wlen % 2) != 0) wlen += 1;
wstatus = s7plcFWdoWrite(station, &station->writeBuffer[woffs], woffs, wlen); if (station->writeAll == 0) {
wstatus = s7plcFWdoWrite(station, &station->writeBuffer[woffs], woffs, wlen);
}
else {
wstatus = s7plcFWdoWrite(station, &station->writeBuffer[0], 0, station->writeSize);
}
if (wstatus != 0) { if (wstatus != 0) {
s7plcFWDebugLog(0, "s7plcFWWriteMaskedArray %s: s7plcFWdoWrite(%d, ...) failed\n", station->name, station->writeSocket); s7plcFWDebugLog(0, "s7plcFWWriteMaskedArray %s: s7plcFWdoWrite(%d, ...) failed\n", station->name, station->writeSocket);
s7plcFWCloseConnection(station, FOR_WRITE); s7plcFWCloseConnection(station, FOR_WRITE);
@ -911,12 +920,12 @@ STATIC int s7plcFWWaitForInput(s7plcFWStation* station, int which, double timeou
errno = 0; errno = 0;
while ((iSelect=select(socket+1, &socklist, 0, 0, &to)) < 0) { while ((iSelect=select(socket+1, &socklist, 0, 0, &to)) < 0) {
if (errno != EINTR) { if (errno != EINTR) {
s7plcFWDebugLog(0, "s7plcFWWaitForInput %s: select(%d, %f sec) failed: %s\n", station->name, socket, timeout, strerror(errno)); s7plcFWDebugLog(0, "s7plcFWWaitForInput %s: select(%d, %d ms) failed: %s\n", station->name, socket, (int)(timeout * 1000.0), strerror(errno));
return -1; return -1;
} }
} }
if (iSelect==0 && timeout > 0) { /* timed out */ if (iSelect==0 && timeout > 0) { /* timed out */
s7plcFWDebugLog(0, "s7plcFWWaitForInput %s: select(%d, %f sec) timed out\n", station->name, socket, timeout); s7plcFWDebugLog(0, "s7plcFWWaitForInput %s: select(%d, %d ms) timed out\n", station->name, socket, (int)(timeout * 1000.0));
errno = ETIMEDOUT; errno = ETIMEDOUT;
} }
return iSelect; return iSelect;
@ -955,7 +964,7 @@ STATIC int s7plcFWEstablishConnection(s7plcFWStation* station, int which)
to.tv_usec=(int)(CONNECT_TIMEOUT-to.tv_sec)*1000000; to.tv_usec=(int)(CONNECT_TIMEOUT-to.tv_sec)*1000000;
#ifdef __vxworks #ifdef __vxworks
if (connectWithTimeout(socket, (struct sockaddr *) &serverAddr, sizeof (serverAddr), &to) < 0) { if (connectWithTimeout(socket, (struct sockaddr *) &serverAddr, sizeof (serverAddr), &to) < 0) {
s7plcFWDebugLog(0, "s7plcFWEstablishConnection %s: connectWithTimeout(%d,...,%g sec) failed: %s\n", station->name, socket, CONNECT_TIMEOUT, strerror(errno)); s7plcFWDebugLog(0, "s7plcFWEstablishConnection %s: connectWithTimeout(%d,...,%d ms) failed: %s\n", station->name, socket, (int)(CONNECT_TIMEOUT * 1000.0), strerror(errno));
return -1; return -1;
} }
#else #else
@ -981,12 +990,12 @@ STATIC int s7plcFWEstablishConnection(s7plcFWStation* station, int which)
/* wait for connection */ /* wait for connection */
while ((status = select(socket+1, NULL, &fdset, NULL, &to)) < 0) { while ((status = select(socket+1, NULL, &fdset, NULL, &to)) < 0) {
if (errno != EINTR) { if (errno != EINTR) {
s7plcFWDebugLog(0, "s7plcFWEstablishConnection %s: select(%d, %f sec) failed: %s\n", station->name, socket, CONNECT_TIMEOUT, strerror(errno)); s7plcFWDebugLog(0, "s7plcFWEstablishConnection %s: select(%d, %d ms) failed: %s\n", station->name, socket, (int)(CONNECT_TIMEOUT * 1000.0), strerror(errno));
return -1; return -1;
} }
} }
if (status == 0) { if (status == 0) {
s7plcFWDebugLog(0, "s7plcFWEstablishConnection %s: select(%d, %f sec) timed out\n", station->name, socket, CONNECT_TIMEOUT); s7plcFWDebugLog(0, "s7plcFWEstablishConnection %s: select(%d, %d ms) timed out\n", station->name, socket, (int)(CONNECT_TIMEOUT * 1000.0));
errno = ETIMEDOUT; errno = ETIMEDOUT;
return -1; return -1;
} }

View File

@ -54,6 +54,7 @@ Besides the
<li>new communication protocol (FETCH/WRITE)</li> <li>new communication protocol (FETCH/WRITE)</li>
<li>the modified <code>s7plcFWConfigure</code> function</li> <li>the modified <code>s7plcFWConfigure</code> function</li>
<li>additional support for write-connection-status (see <a href="#stat"> <code>"s7plcFW&nbsp;stat2"</code> </a>)</li> <li>additional support for write-connection-status (see <a href="#stat"> <code>"s7plcFW&nbsp;stat2"</code> </a>)</li>
<li>when using bi and bo bits 0-7 and 8-15 are swapped (i.e. for bit 3 use 3+8=11, or for bit 13 use 13-8=5)</li>
</ol> </ol>
there should be no other differences. there should be no other differences.
<br><br> <br><br>
@ -122,6 +123,9 @@ containing the
and and
<code>"writePort,writeOrg,writeDb,writeOffsetInDb,writeSizeOfDb"</code>. <code>"writePort,writeOrg,writeDb,writeOffsetInDb,writeSizeOfDb"</code>.
<br> <br>
For <code><i>writeInfo</i></code> you can add at the end of string an <code><i>writeall</i></code> option,
to allways write the whole buffer to DB. This is needed for PLCs as used in SINQ.
<br>
fetchPort and writePort come in pairs. Usualy starting at 2000,2001. fetchPort and writePort come in pairs. Usualy starting at 2000,2001.
<br> <br>
Offsets and Sizes are in bytes and must be <code>even numbers</code>. Offset will usualy be zero, but one does not neccessarilly have to start at the beginning of Db. The size is number of bytes to fetch or write starting from given offset - it does not have to go to the end of Db and it should never exceed the size of Db. Offsets and Sizes are in bytes and must be <code>even numbers</code>. Offset will usualy be zero, but one does not neccessarilly have to start at the beginning of Db. The size is number of bytes to fetch or write starting from given offset - it does not have to go to the end of Db and it should never exceed the size of Db.