/* $Author: anicic $ */ /* $Date: 2012/03/06 10:53:08 $ */ /* $Id: devS7plcFW.c,v 1.2 2012/03/06 10:53:08 anicic Exp $ */ /* $Name: $ */ /* $Revision: 1.2 $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BASE_VERSION #define EPICS_3_13 #include "compat3_13.h" #else #include #include #include #include #endif /* suppress compiler warning concerning long long with __extension__ */ #if (!defined __GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) #define __extension__ #endif #ifndef epicsUInt64 #if (LONG_MAX > 2147483647L) #define epicsUInt64 unsigned long #define CONV64 "%016lx" #else #define epicsUInt64 unsigned long long #define CONV64 "%016llx" #endif #endif #define S7MEM_TIME 100 typedef struct { /* Private structure to save IO arguments */ s7plcFWStation *station; /* Card id */ unsigned short offs; /* Offset (in bytes) within memory block */ unsigned short bit; /* Bit number (0-15) for bi/bo */ unsigned short dtype; /* Data type */ unsigned short dlen; /* Data length (in bytes) */ epicsInt32 hwLow; /* Hardware Low limit */ epicsInt32 hwHigh; /* Hardware High limit */ } S7memPrivate_t; static char cvsid_devS7plcFW[] = "$Id: devS7plcFW.c,v 1.2 2012/03/06 10:53:08 anicic Exp $"; STATIC long s7plcFWReport(); STATIC int s7plcFWIoParse(char* recordName, char *parameters, S7memPrivate_t *); STATIC long s7plcFWGetInIntInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt); STATIC long s7plcFWGetOutIntInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt); struct devsup { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN io; }; /* bi for status bit ************************************************/ STATIC long s7plcFWInitRecordStat(biRecord *); STATIC long s7plcFWReadStat(biRecord *); STATIC long s7plcFWReadStat2(biRecord *); struct devsup s7plcFWStat = { 5, NULL, NULL, s7plcFWInitRecordStat, s7plcFWGetInIntInfo, s7plcFWReadStat }; epicsExportAddress(dset, s7plcFWStat); struct devsup s7plcFWStat2 = { 5, NULL, NULL, s7plcFWInitRecordStat, s7plcFWGetInIntInfo, s7plcFWReadStat2 }; epicsExportAddress(dset, s7plcFWStat2); /* bi ***************************************************************/ STATIC long s7plcFWInitRecordBi(biRecord *); STATIC long s7plcFWReadBi(biRecord *); struct devsup s7plcFWBi = { 5, NULL, NULL, s7plcFWInitRecordBi, s7plcFWGetInIntInfo, s7plcFWReadBi }; epicsExportAddress(dset, s7plcFWBi); /* bo ***************************************************************/ STATIC long s7plcFWInitRecordBo(boRecord *); STATIC long s7plcFWWriteBo(boRecord *); struct devsup s7plcFWBo = { 5, NULL, NULL, s7plcFWInitRecordBo, s7plcFWGetOutIntInfo, s7plcFWWriteBo }; epicsExportAddress(dset, s7plcFWBo); /* mbbi *************************************************************/ STATIC long s7plcFWInitRecordMbbi(mbbiRecord *); STATIC long s7plcFWReadMbbi(mbbiRecord *); struct devsup s7plcFWMbbi = { 5, NULL, NULL, s7plcFWInitRecordMbbi, s7plcFWGetInIntInfo, s7plcFWReadMbbi }; epicsExportAddress(dset, s7plcFWMbbi); /* mbbo *************************************************************/ STATIC long s7plcFWInitRecordMbbo(mbboRecord *); STATIC long s7plcFWWriteMbbo(mbboRecord *); struct devsup s7plcFWMbbo = { 5, NULL, NULL, s7plcFWInitRecordMbbo, s7plcFWGetOutIntInfo, s7plcFWWriteMbbo }; epicsExportAddress(dset, s7plcFWMbbo); /* mbbiDirect *******************************************************/ STATIC long s7plcFWInitRecordMbbiDirect(mbbiDirectRecord *); STATIC long s7plcFWReadMbbiDirect(mbbiDirectRecord *); struct devsup s7plcFWMbbiDirect = { 5, s7plcFWReport, NULL, s7plcFWInitRecordMbbiDirect, s7plcFWGetInIntInfo, s7plcFWReadMbbiDirect }; epicsExportAddress(dset, s7plcFWMbbiDirect); /* mbboDirect *******************************************************/ STATIC long s7plcFWInitRecordMbboDirect(mbboDirectRecord *); STATIC long s7plcFWWriteMbboDirect(mbboDirectRecord *); struct devsup s7plcFWMbboDirect = { 5, NULL, NULL, s7plcFWInitRecordMbboDirect, s7plcFWGetOutIntInfo, s7plcFWWriteMbboDirect }; epicsExportAddress(dset, s7plcFWMbboDirect); /* longin ***********************************************************/ STATIC long s7plcFWInitRecordLongin(longinRecord *); STATIC long s7plcFWReadLongin(longinRecord *); struct devsup s7plcFWLongin = { 5, NULL, NULL, s7plcFWInitRecordLongin, s7plcFWGetInIntInfo, s7plcFWReadLongin }; epicsExportAddress(dset, s7plcFWLongin); /* longout **********************************************************/ STATIC long s7plcFWInitRecordLongout(longoutRecord *); STATIC long s7plcFWWriteLongout(longoutRecord *); struct devsup s7plcFWLongout = { 5, NULL, NULL, s7plcFWInitRecordLongout, s7plcFWGetOutIntInfo, s7plcFWWriteLongout }; epicsExportAddress(dset, s7plcFWLongout); /* ai ***************************************************************/ STATIC long s7plcFWInitRecordAi(aiRecord *); STATIC long s7plcFWReadAi(aiRecord *); STATIC long s7plcFWSpecialLinconvAi(aiRecord *, int after); struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read; DEVSUPFUN special_linconv; } s7plcFWAi = { 6, NULL, NULL, s7plcFWInitRecordAi, s7plcFWGetInIntInfo, s7plcFWReadAi, s7plcFWSpecialLinconvAi }; epicsExportAddress(dset, s7plcFWAi); /* ao ***************************************************************/ STATIC long s7plcFWInitRecordAo(aoRecord *); STATIC long s7plcFWWriteAo(aoRecord *); STATIC long s7plcFWSpecialLinconvAo(aoRecord *, int after); struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN write; DEVSUPFUN special_linconv; } s7plcFWAo = { 6, NULL, NULL, s7plcFWInitRecordAo, s7plcFWGetOutIntInfo, s7plcFWWriteAo, s7plcFWSpecialLinconvAo }; epicsExportAddress(dset, s7plcFWAo); /* stringin *********************************************************/ STATIC long s7plcFWInitRecordStringin(stringinRecord *); STATIC long s7plcFWReadStringin(stringinRecord *); struct devsup s7plcFWStringin = { 5, NULL, NULL, s7plcFWInitRecordStringin, s7plcFWGetInIntInfo, s7plcFWReadStringin }; epicsExportAddress(dset, s7plcFWStringin); /* stringout ********************************************************/ STATIC long s7plcFWInitRecordStringout(stringoutRecord *); STATIC long s7plcFWWriteStringout(stringoutRecord *); struct devsup s7plcFWStringout = { 5, NULL, NULL, s7plcFWInitRecordStringout, s7plcFWGetOutIntInfo, s7plcFWWriteStringout }; epicsExportAddress(dset, s7plcFWStringout); /* waveform *********************************************************/ STATIC long s7plcFWInitRecordWaveform(waveformRecord *); STATIC long s7plcFWReadWaveform(waveformRecord *); struct devsup s7plcFWWaveform = { 5, NULL, NULL, s7plcFWInitRecordWaveform, s7plcFWGetInIntInfo, s7plcFWReadWaveform }; epicsExportAddress(dset, s7plcFWWaveform); /* calcout **********************************************************/ #ifndef EPICS_3_13 STATIC long s7plcFWInitRecordCalcout(calcoutRecord *); STATIC long s7plcFWWriteCalcout(calcoutRecord *); struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN write; DEVSUPFUN special_linconv; } s7plcFWCalcout = { 6, NULL, NULL, s7plcFWInitRecordCalcout, s7plcFWGetOutIntInfo, s7plcFWWriteCalcout, NULL }; epicsExportAddress(dset, s7plcFWCalcout); #endif /********* Report routine ********************************************/ STATIC long s7plcFWReport() { printf("devS7mem version: %s\n", cvsid_devS7plcFW); return 0; } /********* Support for "I/O Intr" for input records ******************/ STATIC long s7plcFWGetInIntInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt) { S7memPrivate_t* p = record->dpvt; if (p == NULL) { recGblRecordError(S_db_badField, record, "s7plcFWGetInIntInfo: uninitialized record"); return -1; } *ppvt = s7plcFWGetFetchScanPvt(p->station); return 0; } /********* Support for "I/O Intr" for output records ****************/ STATIC long s7plcFWGetOutIntInfo(int cmd, dbCommon *record, IOSCANPVT *ppvt) { S7memPrivate_t* p = record->dpvt; if (p == NULL) { recGblRecordError(S_db_badField, record, "s7plcFWGetInIntInfo: uninitialized record"); return -1; } *ppvt = s7plcFWGetWriteScanPvt(p->station); return 0; } /*********************************************************************** * Routine to parse IO arguments * IO address line format: * * /[+] [T=] [B=] [L=] [H=] * * where: - symbolic device name * - address (byte number) within memory block * - parameters to be passed to a particular * devSup parsering routine * - INT8, INT16, INT32, * UINT16 (or UNSIGN16), UINT32 (or UNSIGN32), * REAL32 (or FLOAT), REAL64 (or DOUBLE), * STRING,TIME * - least significant bit is 0 * - raw value that mapps to EGUL * - raw value that mapps to EGUF **********************************************************************/ STATIC int s7plcFWIoParse(char* recordName, char *par, S7memPrivate_t *priv) { char devName[255]; char *p = par, separator; int nchar, i; int status = 0; struct {char* name; int dlen; epicsType type;} datatypes [] = { { "INT8", 1, epicsInt8T }, { "UINT8", 1, epicsUInt8T }, { "UNSIGN8", 1, epicsUInt8T }, { "BYTE", 1, epicsUInt8T }, { "CHAR", 1, epicsUInt8T }, { "INT16", 2, epicsInt16T }, { "SHORT", 2, epicsInt16T }, { "UINT16", 2, epicsUInt16T }, { "UNSIGN16", 2, epicsUInt16T }, { "WORD", 2, epicsUInt16T }, { "INT32", 4, epicsInt32T }, { "LONG", 4, epicsInt32T }, { "UINT32", 4, epicsUInt32T }, { "UNSIGN32", 4, epicsUInt32T }, { "DWORD", 4, epicsUInt32T }, { "REAL32", 4, epicsFloat32T }, { "FLOAT32", 4, epicsFloat32T }, { "FLOAT", 4, epicsFloat32T }, { "REAL64", 8, epicsFloat64T }, { "FLOAT64", 8, epicsFloat64T }, { "DOUBLE", 8, epicsFloat64T }, { "TIME", 1, S7MEM_TIME }, { "BCD", 1, S7MEM_TIME } }; /* Get rid of leading whitespace and non-alphanumeric chars */ while (!isalnum((unsigned char)*p)) if (*p++ == '\0') return S_drv_badParam; /* Get device name */ nchar = strcspn(p, "/"); strncpy(devName, p, nchar); devName[nchar] = '\0'; p += nchar; separator = *p++; s7plcFWDebugLog(1, "s7plcFWIoParse %s: station=%s\n", recordName, devName); priv->station = s7plcFWOpen(devName); if (!priv->station) { errlogSevPrintf(errlogFatal, "s7plcFWIoParse %s: device not found\n", recordName); return S_drv_noDevice; } /* Check station offset */ if (separator == '/') { priv->offs = strtol(p, &p, 0); separator = *p++; /* Handle any number of optional +o additions to the offs */ while (separator == '+') { priv->offs += strtol(p, &p, 0); separator = *p++; } } else { priv->offs = 0; } s7plcFWDebugLog(1, "s7plcFWIoParse %s: offs=%d\n", recordName, priv->offs); /* set default values for parameters */ if (!priv->dtype && !priv->dlen) { priv->dtype = epicsInt16T; priv->dlen = 2; } priv->bit = 0; priv->hwLow = 0; priv->hwHigh = 0; /* allow whitespaces before parameter for device support */ while ((separator == '\t') || (separator == ' ')) separator = *p++; /* handle parameter for device support if present */ nchar = 0; if (separator != '\'') p--; /* quote is optional*/ /* parse parameters */ while (p && *p) { switch (*p) { case ' ': case '\t': p++; break; case 'T': /* T= */ p+=2; if (strncmp(p,"STRING",6) == 0) { priv->dtype = epicsStringT; p += 6; } else { static int maxtype = sizeof(datatypes)/sizeof(*datatypes); for (i = 0; i < maxtype; i++) { nchar = strlen(datatypes[i].name); if (strncmp(p, datatypes[i].name, nchar) == 0) { priv->dtype = datatypes[i].type; priv->dlen = datatypes[i].dlen; p += nchar; break; } } if (i == maxtype) { errlogSevPrintf(errlogFatal, "s7plcFWIoParse %s: invalid datatype %s\n", recordName, p); return S_drv_badParam; } } break; case 'B': /* B= */ p += 2; priv->bit = strtol(p,&p,0); break; case 'L': /* L= (converts to EGUL)*/ p += 2; priv->hwLow = strtol(p,&p,0); break; case 'H': /* L= (converts to EGUF)*/ p += 2; priv->hwHigh = strtol(p,&p,0); break; case '\'': if (separator == '\'') { p = 0; break; } default: errlogSevPrintf(errlogFatal, "s7plcFWIoParse %s: unknown parameter '%c'\n", recordName, *p); return S_drv_badParam; } } /* for T=STRING L=... means length, not low */ if (priv->dtype == epicsStringT && priv->hwLow) { priv->dlen = priv->hwLow; priv->hwLow = 0; } /* check if bit number is in range */ if (priv->bit && priv->bit >= priv->dlen*8) { errlogSevPrintf(errlogFatal, "s7plcFWIoParse %s: invalid bit number %d (>%d)\n", recordName, priv->bit, priv->dlen*8-1); return S_drv_badParam; } /* get default values for L and H if user did'n define them */ switch (priv->dtype) { case epicsUInt8T: if (priv->hwHigh > 0xFF) status = S_drv_badParam; if (!priv->hwHigh) priv->hwLow = 0x00; if (!priv->hwHigh) priv->hwHigh = 0xFF; break; case epicsUInt16T: if (priv->hwHigh > 0xFFFF) status = S_drv_badParam; if (!priv->hwHigh) priv->hwLow = 0x0000; if (!priv->hwHigh) priv->hwHigh = 0xFFFF; break; case epicsUInt32T: if (!priv->hwHigh) priv->hwLow = 0x00000000; if (!priv->hwHigh) priv->hwHigh = 0xFFFFFFFF; break; case epicsInt8T: if (priv->hwHigh > 0x7F) status = S_drv_badParam; if (!priv->hwHigh) priv->hwLow = 0xFFFFFF81; if (!priv->hwHigh) priv->hwHigh = 0x0000007F; break; case epicsInt16T: if (priv->hwHigh > 0x7FFF) status = S_drv_badParam; if (!priv->hwHigh) priv->hwLow = 0xFFFF8001; if (!priv->hwHigh) priv->hwHigh = 0x00007FFF; break; case epicsInt32T: if (!priv->hwHigh) priv->hwLow = 0x80000001; if (!priv->hwHigh) priv->hwHigh = 0x7FFFFFFF; break; default: if (priv->hwHigh || priv->hwLow) { errlogSevPrintf(errlogMinor, "s7plcFWIoParse %s: L or H makes" " no sense with this data type\n", recordName); } break; } s7plcFWDebugLog(1, "s7plcFWIoParse %s: dlen=%d\n",recordName, priv->dlen); s7plcFWDebugLog(1, "s7plcFWIoParse %s: B=%d\n", recordName, priv->bit); s7plcFWDebugLog(1, "s7plcFWIoParse %s: L=%#x\n", recordName, priv->hwLow); s7plcFWDebugLog(1, "s7plcFWIoParse %s: H=%#x\n", recordName, priv->hwHigh); if (status) { errlogSevPrintf(errlogMinor, "s7plcFWIoParse %s: L or H out of range for this data type\n", recordName); return status; } return 0; } /* bi for status bit ************************************************/ STATIC long s7plcFWInitRecordStat(biRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordStat: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordStat"); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordStat: bad INP field"); return S_db_badField; } assert(priv->station); record->dpvt = priv; return 0; } STATIC long s7plcFWReadStat(biRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); /* psudo-read (0 bytes, 0 data len, which 1=fetch-status 2 =write-status) just to get the connection status */ status = s7plcFWReadArray(priv->station, 1, 0, 0, NULL); if (status == S_drv_noConn) { /* errlogSevPrintf(errlogFatal, "%s: read error - no connection\n", record->name); */ record->rval = 0; return 0; } if (status) { recGblSetSevr(record, READ_ALARM, INVALID_ALARM); return status; } record->rval = 1; return 0; } STATIC long s7plcFWReadStat2(biRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); /* psudo-read (0 bytes, 0 data len, which 0=fetch-status 1 =write-status) just to get the connection status */ status = s7plcFWReadArray(priv->station, 2, 0, 0, NULL); if (status == S_drv_noConn) { /* errlogSevPrintf(errlogFatal, "%s: read error - no connection\n", record->name); */ record->rval = 0; return 0; } if (status) { recGblSetSevr(record, READ_ALARM, INVALID_ALARM); return status; } record->rval = 1; return 0; } /* bi ***************************************************************/ STATIC long s7plcFWInitRecordBi(biRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordBi: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordBi"); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordBi: bad INP field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordBi %s: illegal data type\n", record->name); return S_db_badField; } record->mask = 1 << priv->bit; record->dpvt = priv; return 0; } STATIC long s7plcFWReadBi(biRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8; epicsUInt16 rval16; epicsUInt32 rval32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &rval8); s7plcFWDebugLog(3, "bi %s: read 8bit %02x\n", record->name, rval8); rval32 = rval8; break; case epicsInt16T: case epicsUInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &rval16); s7plcFWDebugLog(3, "bi %s: read 16bit %04x\n", record->name, rval16); rval32 = rval16; break; case epicsInt32T: case epicsUInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &rval32); s7plcFWDebugLog(3, "bi %s: read 32bit %04x\n", record->name, rval32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } record->rval = rval32 & record->mask; if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); } return status; } /* bo ***************************************************************/ STATIC long s7plcFWInitRecordBo(boRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordBo: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordBo"); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordBo: bad OUT field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordBo %s: illegal data type\n", record->name); return S_db_badField; } record->mask = 1 << priv->bit; record->dpvt = priv; return 2; /* preserve whatever is in the VAL field */ } STATIC long s7plcFWWriteBo(boRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8, mask8; epicsUInt16 rval16, mask16; epicsUInt32 rval32, mask32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: rval8 = record->rval; mask8 = record->mask; s7plcFWDebugLog(2, "bo %s: write 8bit %02x mask %02x\n", record->name, rval8, mask8); status = s7plcFWWriteMasked(priv->station, priv->offs, 1, &rval8, &mask8); break; case epicsInt16T: case epicsUInt16T: rval16 = record->rval; mask16 = record->mask; s7plcFWDebugLog(2, "bo %s: write 16bit %04x mask %04x\n", record->name, rval16, mask16); status = s7plcFWWriteMasked(priv->station, priv->offs, 2, &rval16, &mask16); break; case epicsInt32T: case epicsUInt32T: rval32 = record->rval; mask32 = record->mask; s7plcFWDebugLog(2, "bo %s: write 32bit %08x mask %08x\n", record->name, rval32, mask32); status = s7plcFWWriteMasked(priv->station, priv->offs, 4, &rval32, &mask32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } /* mbbi *************************************************************/ STATIC long s7plcFWInitRecordMbbi(mbbiRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbbi: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordMbbi"); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbbi: bad INP field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordMbbi %s: illegal data type\n", record->name); return S_db_badField; } if (record->shft > 0) record->mask <<= record->shft; record->dpvt = priv; return 0; } STATIC long s7plcFWReadMbbi(mbbiRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8; epicsUInt16 rval16; epicsUInt32 rval32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &rval8); s7plcFWDebugLog(3, "mbbi %s: read 8bit %02x\n", record->name, rval8); rval32 = rval8; break; case epicsInt16T: case epicsUInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &rval16); s7plcFWDebugLog(3, "mbbi %s: read 16bit %04x\n", record->name, rval16); rval32 = rval16; break; case epicsInt32T: case epicsUInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &rval32); s7plcFWDebugLog(3, "mbbi %s: read 32bit %04x\n", record->name, rval32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } record->rval = rval32 & record->mask; if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); } return status; } /* mbbo *************************************************************/ STATIC long s7plcFWInitRecordMbbo(mbboRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbbo: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordMbbo"); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbbo: bad OUT field"); return S_db_badField; } assert(priv->station); if (record->shft > 0) record->mask <<= record->shft; switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordMbbo %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; return 2; /* preserve whatever is in the VAL field */ } STATIC long s7plcFWWriteMbbo(mbboRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8, mask8; epicsUInt16 rval16, mask16; epicsUInt32 rval32, mask32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: rval8 = record->rval; mask8 = record->mask; s7plcFWDebugLog(2, "mbbo %s: write 8bit %02x mask %02x\n", record->name, rval8, mask8); status = s7plcFWWriteMasked(priv->station, priv->offs, 1, &rval8, &mask8); break; case epicsInt16T: case epicsUInt16T: rval16 = record->rval; mask16 = record->mask; s7plcFWDebugLog(2, "mbbo %s: write 16bit %04x mask %04x\n", record->name, rval16, mask16); status = s7plcFWWriteMasked(priv->station, priv->offs, 2, &rval16, &mask16); break; case epicsInt32T: case epicsUInt32T: rval32 = record->rval; mask32 = record->mask; s7plcFWDebugLog(2, "mbbo %s: write 32bit %08x mask %08x\n", record->name, rval32, mask32); status = s7plcFWWriteMasked(priv->station, priv->offs, 4, &rval32, &mask32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } /* mbbiDirect *******************************************************/ STATIC long s7plcFWInitRecordMbbiDirect(mbbiDirectRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbbiDirect: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordMbbiDirect"); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbbiDirect: bad INP field"); return S_db_badField; } assert(priv->station); if (record->shft > 0) record->mask <<= record->shft; switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordMbbiDirect %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; return 0; } STATIC long s7plcFWReadMbbiDirect(mbbiDirectRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8; epicsUInt16 rval16; epicsUInt32 rval32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &rval8); s7plcFWDebugLog(3, "mbbiDirect %s: read 8bit %02x\n", record->name, rval8); rval32 = rval8; break; case epicsInt16T: case epicsUInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &rval16); s7plcFWDebugLog(3, "mbbiDirect %s: read 16bit %04x\n", record->name, rval16); rval32 = rval16; break; case epicsInt32T: case epicsUInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &rval32); s7plcFWDebugLog(3, "mbbiDirect %s: read 32bit %08x\n", record->name, rval32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } record->rval = rval32 & record->mask; if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); } return status; } /* mbboDirect *******************************************************/ STATIC long s7plcFWInitRecordMbboDirect(mbboDirectRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbboDirect: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordMbboDirect"); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordMbboDirect: bad OUT field"); return S_db_badField; } assert(priv->station); if (record->shft > 0) record->mask <<= record->shft; switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordMbboDirect %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; return 2; /* preserve whatever is in the VAL field */ } STATIC long s7plcFWWriteMbboDirect(mbboDirectRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8, mask8; epicsUInt16 rval16, mask16; epicsUInt32 rval32, mask32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: rval8 = record->rval; mask8 = record->mask; s7plcFWDebugLog(2, "mbboDirect %s: write 8bit %02x mask %02x\n", record->name, rval8, mask8); status = s7plcFWWriteMasked(priv->station, priv->offs, 1, &rval8, &mask8); break; case epicsInt16T: case epicsUInt16T: rval16 = record->rval; mask16 = record->mask; s7plcFWDebugLog(2, "mbboDirect %s: write 16bit %04x mask %04x\n", record->name, rval16, mask16); status = s7plcFWWriteMasked(priv->station, priv->offs, 2, &rval16, &mask16); break; case epicsInt32T: case epicsUInt32T: rval32 = record->rval; mask32 = record->mask; s7plcFWDebugLog(2, "mbboDirect %s: write 32bit %08x mask %08x\n", record->name, rval32, mask32); status = s7plcFWWriteMasked(priv->station, priv->offs, 4, &rval32, &mask32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } /* longin ***********************************************************/ STATIC long s7plcFWInitRecordLongin(longinRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordLongin: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordLongin"); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordLongin: bad INP field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordLongin %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; return 0; } STATIC long s7plcFWReadLongin(longinRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; signed char sval8; epicsUInt8 uval8; epicsInt16 sval16; epicsUInt16 uval16; epicsInt32 sval32; epicsUInt32 uval32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &sval8); s7plcFWDebugLog(3, "longin %s: read 8bit %02x\n", record->name, sval8); record->val = sval8; break; case epicsUInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &uval8); s7plcFWDebugLog(3, "longin %s: read 8bit %02x\n", record->name, uval8); record->val = uval8; break; case epicsInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &sval16); s7plcFWDebugLog(3, "longin %s: read 16bit %04x\n", record->name, sval16); record->val = sval16; break; case epicsUInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &uval16); s7plcFWDebugLog(3, "longin %s: read 16bit %04x\n", record->name, sval16); record->val = uval16; break; case epicsInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &sval32); s7plcFWDebugLog(3, "longin %s: read 32bit %04x\n", record->name, sval32); record->val = sval32; break; case epicsUInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &uval32); s7plcFWDebugLog(3, "longin %s: read 32bit %04x\n", record->name, uval32); record->val = uval32; break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); } return status; } /* longout **********************************************************/ STATIC long s7plcFWInitRecordLongout(longoutRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordLongout: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordLongout"); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordLongout: bad OUT field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordLongout %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; return 0; } STATIC long s7plcFWWriteLongout(longoutRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8; epicsUInt16 rval16; epicsUInt32 rval32; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: rval8 = record->val; s7plcFWDebugLog(2, "longout %s: write 8bit %02x\n", record->name, rval8); status = s7plcFWWrite(priv->station, priv->offs, 1, &rval8); break; case epicsInt16T: case epicsUInt16T: rval16 = record->val; s7plcFWDebugLog(2, "longout %s: write 16bit %04x\n", record->name, rval16); status = s7plcFWWrite(priv->station, priv->offs, 2, &rval16); break; case epicsInt32T: case epicsUInt32T: rval32 = record->val; s7plcFWDebugLog(2, "longout %s: write 32bit %08x\n", record->name, rval32); status = s7plcFWWrite(priv->station, priv->offs, 4, &rval32); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } /* ai ***************************************************************/ STATIC long s7plcFWInitRecordAi(aiRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordAi: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordAi"); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordAi: bad INP field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: case epicsFloat32T: case epicsFloat64T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordAi %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; s7plcFWSpecialLinconvAi(record, TRUE); return 0; } STATIC long s7plcFWReadAi(aiRecord *record) { int status, floatval = FALSE; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; signed char sval8; unsigned char uval8; epicsInt16 sval16; epicsUInt16 uval16; epicsInt32 sval32; epicsUInt32 uval32; union {epicsFloat32 f; epicsUInt32 i; } val32; __extension__ union {epicsFloat64 f; epicsUInt64 i; } val64; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &sval8); s7plcFWDebugLog(3, "ai %s: read 8bit %02x\n", record->name, sval8); record->rval = sval8; break; case epicsUInt8T: status = s7plcFWRead(priv->station, priv->offs, 1, &uval8); s7plcFWDebugLog(3, "ai %s: read 8bit %02x\n", record->name, uval8); record->rval = uval8; break; case epicsInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &sval16); s7plcFWDebugLog(3, "ai %s: read 16bit %04x\n", record->name, sval16); record->rval = sval16; break; case epicsUInt16T: status = s7plcFWRead(priv->station, priv->offs, 2, &uval16); s7plcFWDebugLog(3, "ai %s: read 16bit %04x\n", record->name, uval16); record->rval = uval16; break; case epicsInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &sval32); s7plcFWDebugLog(3, "ai %s: read 32bit %04x\n", record->name, sval32); record->rval = sval32; break; case epicsUInt32T: status = s7plcFWRead(priv->station, priv->offs, 4, &uval32); s7plcFWDebugLog(3, "ai %s: read 32bit %04x\n", record->name, uval32); record->rval = uval32; break; case epicsFloat32T: status = s7plcFWRead(priv->station, priv->offs, 4, &val32); s7plcFWDebugLog(3, "ai %s: read 32bit %04x = %g\n", record->name, val32.i, val32.f); val64.f = val32.f; floatval = TRUE; break; case epicsFloat64T: status = s7plcFWRead(priv->station, priv->offs, 8, &val64); __extension__ s7plcFWDebugLog(3, "ai %s: read 64bit " CONV64 " = %g\n", record->name, val64.i, val64.f); floatval = TRUE; break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); return status; } if (floatval) { /* emulate scaling */ if (record->aslo != 0.0) val64.f *= record->aslo; val64.f += record->aoff; if (record->udf) record->val = val64.f; else /* emulate smoothing */ record->val = record->val * record->smoo + val64.f * (1.0 - record->smoo); record->udf = FALSE; return 2; } return 0; } STATIC long s7plcFWSpecialLinconvAi(aiRecord *record, int after) { epicsUInt32 hwSpan; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; if (after) { hwSpan = priv->hwHigh - priv->hwLow; record->eslo = (record->eguf - record->egul) / hwSpan; record->eoff = (priv->hwHigh*record->egul - priv->hwLow*record->eguf) / hwSpan; } return 0; } /* ao ***************************************************************/ STATIC long s7plcFWInitRecordAo(aoRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordAo: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordAo"); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordAo: bad OUT field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: case epicsFloat32T: case epicsFloat64T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordAo %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; s7plcFWSpecialLinconvAo(record, TRUE); return 2; /* preserve whatever is in the VAL field */ } STATIC long s7plcFWWriteAo(aoRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 rval8; epicsUInt16 rval16; epicsUInt32 rval32; union {epicsFloat32 f; epicsUInt32 i; } val32; __extension__ union {epicsFloat64 f; epicsUInt64 i; } val64; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); rval32 = record->rval; switch (priv->dtype) { case epicsInt8T: if (record->rval > priv->hwHigh) rval32 = priv->hwHigh; if (record->rval < priv->hwLow) rval32 = priv->hwLow; rval8 = rval32; s7plcFWDebugLog(2, "ao %s: write 8bit %02x\n", record->name, rval8 & 0xff); status = s7plcFWWrite(priv->station, priv->offs, 1, &rval8); break; case epicsUInt8T: if (rval32 > (epicsUInt32)priv->hwHigh) rval32 = priv->hwHigh; if (rval32 < (epicsUInt32)priv->hwLow) rval32 = priv->hwLow; rval8 = rval32; s7plcFWDebugLog(2, "ao %s: write 8bit %02x\n", record->name, rval8 & 0xff); status = s7plcFWWrite(priv->station, priv->offs, 1, &rval8); break; case epicsInt16T: if (record->rval > priv->hwHigh) rval32 = priv->hwHigh; if (record->rval < priv->hwLow) rval32 = priv->hwLow; rval16 = rval32; s7plcFWDebugLog(2, "ao %s: write 16bit %04x\n", record->name, rval16 & 0xffff); status = s7plcFWWrite(priv->station, priv->offs, 2, &rval16); break; case epicsUInt16T: if (rval32 > (epicsUInt32)priv->hwHigh) rval32 = priv->hwHigh; if (rval32 < (epicsUInt32)priv->hwLow) rval32 = priv->hwLow; rval16 = rval32; s7plcFWDebugLog(2, "ao %s: write 16bit %04x\n", record->name, rval16 & 0xffff); status = s7plcFWWrite(priv->station, priv->offs, 2, &rval16); break; case epicsInt32T: if (record->rval > priv->hwHigh) rval32 = priv->hwHigh; if (record->rval < priv->hwLow) rval32 = priv->hwLow; s7plcFWDebugLog(2, "ao %s: write 32bit %08x\n", record->name, rval32); status = s7plcFWWrite(priv->station, priv->offs, 4, &rval32); break; case epicsUInt32T: if (rval32 > (epicsUInt32)priv->hwHigh) rval32 = priv->hwHigh; if (rval32 < (epicsUInt32)priv->hwLow) rval32 = priv->hwLow; s7plcFWDebugLog(2, "ao %s: write 32bit %08x\n", record->name, rval32); status = s7plcFWWrite(priv->station, priv->offs, 4, &rval32); break; case epicsFloat32T: /* emulate scaling */ val32.f = record->oval - record->aoff; if (record->aslo != 0) val32.f /= record->aslo; s7plcFWDebugLog(2, "ao %s: write 32bit %08x = %g\n", record->name, val32.i, val32.f); status = s7plcFWWrite(priv->station, priv->offs, 4, &val32); break; case epicsFloat64T: /* emulate scaling */ val64.f = record->oval - record->aoff; if (record->aslo != 0) val64.f /= record->aslo; __extension__ s7plcFWDebugLog(2, "ao %s: write 64bit " CONV64 " = %g\n", record->name, val64.i, val64.f); status = s7plcFWWrite(priv->station, priv->offs, 8, &val64); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } STATIC long s7plcFWSpecialLinconvAo(aoRecord *record, int after) { epicsUInt32 hwSpan; S7memPrivate_t *priv = (S7memPrivate_t *) record->dpvt; if (after) { hwSpan = priv->hwHigh - priv->hwLow; record->eslo = (record->eguf - record->egul) / hwSpan; record->eoff = (priv->hwHigh*record->egul -priv->hwLow*record->eguf) / hwSpan; } return 0; } /* stringin *********************************************************/ STATIC long s7plcFWInitRecordStringin(stringinRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordStringin: illegal INP field type"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordStringin"); priv->dtype = epicsStringT; priv->dlen = sizeof(record->val); status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordLongin: bad INP field"); return S_db_badField; } assert(priv->station); if (priv->dtype != epicsStringT) { errlogSevPrintf(errlogFatal, "s7plcFWInitRecordStringin %s: illegal data type\n", record->name); return S_db_badField; } if (priv->dlen > sizeof(record->val)) { errlogSevPrintf(errlogMinor, "%s: string size reduced from %d to %d\n", record->name, priv->dlen, (int)sizeof(record->val)); priv->dlen = sizeof(record->val); } record->dpvt = priv; return 0; } STATIC long s7plcFWReadStringin(stringinRecord *record) { // The SPS includes the max length of the string and the length of the // current string, as the first two bytes in the register. int status; epicsUInt8 uval8; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); status = s7plcFWRead(priv->station, priv->offs+1, 1, &uval8); s7plcFWDebugLog(3, "stringin %s: read 8bit %02x\n", record->name, uval8); uval8 = uval8 <= priv->dlen ? uval8 : priv->dlen; memset(record->val, 0, priv->dlen); status = s7plcFWReadArray(priv->station, priv->offs+2, 1, uval8, record->val); s7plcFWDebugLog(3, "stringin %s: read array of %d 8bit values\n", record->name, uval8); if (record->val[priv->dlen] && !memchr(record->val, 0, priv->dlen)) { /* truncate oversize string */ record->val[priv->dlen] = 0; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); } return status; } /* stringout ********************************************************/ STATIC long s7plcFWInitRecordStringout(stringoutRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordStringout: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordStringout"); priv->dtype = epicsStringT; priv->dlen = sizeof(record->val); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordStringout: bad OUT field"); return S_db_badField; } assert(priv->station); if (priv->dtype != epicsStringT) { errlogSevPrintf(errlogFatal, "s7plcFWInitRecordStringout %s: illegal data type\n", record->name); return S_db_badField; } if (priv->dlen > sizeof(record->val)) { errlogSevPrintf(errlogMinor, "%s: string size reduced from %d to %d\n", record->name, priv->dlen, (int)sizeof(record->val)); priv->dlen = sizeof(record->val); } record->dpvt = priv; return 0; } STATIC long s7plcFWWriteStringout(stringoutRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); s7plcFWDebugLog(2, "stringout %s: write %d 8bit values: \"%.*s\"\n", record->name, priv->dlen, priv->dlen, record->val); status = s7plcFWWriteArray(priv->station, priv->offs, 1, priv->dlen, record->val); if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } /* waveform *********************************************************/ STATIC long s7plcFWInitRecordWaveform(waveformRecord *record) { S7memPrivate_t *priv; int status; if (record->inp.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordWaveform: illegal INP field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordWaveform"); switch (record->ftvl) { case DBF_CHAR: priv->dtype = epicsInt8T; priv->dlen = 1; break; case DBF_UCHAR: priv->dtype = epicsUInt8T; priv->dlen = 1; break; case DBF_SHORT: priv->dtype = epicsInt16T; priv->dlen = 2; break; case DBF_USHORT: priv->dtype = epicsUInt16T; priv->dlen = 2; break; case DBF_LONG: priv->dtype = epicsInt32T; priv->dlen = 4; break; case DBF_ULONG: priv->dtype = epicsUInt32T; priv->dlen = 4; break; case DBF_FLOAT: priv->dtype = epicsFloat32T; priv->dlen = 4; break; case DBF_DOUBLE: priv->dtype = epicsFloat64T; priv->dlen = 8; break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordWaveform %s: illegal FTVL value\n", record->name); return S_db_badField; } status = s7plcFWIoParse(record->name, record->inp.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordWaveform: bad INP field"); return S_db_badField; } assert(priv->station); record->nord = record->nelm; switch (priv->dtype) { case S7MEM_TIME: if ((record->ftvl != DBF_CHAR) && (record->ftvl != DBF_UCHAR)) { status = S_db_badField; } break; case epicsFloat64T: if (record->ftvl != DBF_DOUBLE) { status = S_db_badField; } break; case epicsFloat32T: if (record->ftvl != DBF_FLOAT) { status = S_db_badField; } break; case epicsStringT: if ((record->ftvl == DBF_CHAR) || (record->ftvl == DBF_UCHAR)) { if (!priv->dlen) priv->dlen = record->nelm; if (priv->dlen > record->nelm) priv->dlen = record->nelm; break; } break; case epicsInt8T: case epicsUInt8T: if ((record->ftvl != DBF_CHAR) && (record->ftvl == DBF_UCHAR)) { status = S_db_badField; } break; case epicsInt16T: case epicsUInt16T: if ((record->ftvl != DBF_SHORT) && (record->ftvl == DBF_USHORT)) { status = S_db_badField; } break; case epicsInt32T: case epicsUInt32T: if ((record->ftvl != DBF_LONG) && (record->ftvl == DBF_ULONG)) { status = S_db_badField; } break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordWaveform %s: illegal data type\n", record->name); return S_db_badField; } if (status) { errlogSevPrintf(errlogFatal, "s7plcFWInitRecordWaveform %s: " "wrong FTVL field for this data type", record->name); return status; } record->dpvt = priv; return 0; } /* * bcd2d routine to convert byte from BCD to decimal format. */ static unsigned char bcd2d(unsigned char bcd) { unsigned char tmp; tmp = bcd & 0xF; tmp += ((bcd >> 4) & 0xF)*10; return tmp; } STATIC long s7plcFWReadWaveform(waveformRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; char Time[8]; int i; char *p; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsStringT: status = s7plcFWReadArray(priv->station, priv->offs, 1, record->nelm, record->bptr); s7plcFWDebugLog(3, "waveform %s: read %ld values of 8bit to %p\n", record->name, (long int) record->nelm, record->bptr); break; case epicsInt16T: case epicsUInt16T: status = s7plcFWReadArray(priv->station, priv->offs, 2, record->nelm, record->bptr); s7plcFWDebugLog(3, "waveform %s: read %ld values of 16bit to %p\n", record->name, (long int) record->nelm, record->bptr); break; case epicsInt32T: case epicsUInt32T: case epicsFloat32T: status = s7plcFWReadArray(priv->station, priv->offs, 4, record->nelm, record->bptr); s7plcFWDebugLog(3, "waveform %s: read %ld values of 32bit to %p\n", record->name, (long int) record->nelm, record->bptr); break; case epicsFloat64T: status = s7plcFWReadArray(priv->station, priv->offs, 8, record->nelm, record->bptr); s7plcFWDebugLog(3, "waveform %s: read %ld values of 64bit to %p\n", record->name, (long int) record->nelm, record->bptr); break; case S7MEM_TIME: status = s7plcFWReadArray(priv->station, priv->offs, 1, 8, Time); s7plcFWDebugLog(3, "waveform %s: read 8 values of 8bit to %p\n", record->name, record->bptr); if (status) break; for (i = 0, p = record->bptr; i < record->nelm; i++) *p++ = (i == 7)? Time[i] : bcd2d(Time[i]); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } record->nord = record->nelm; if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { errlogSevPrintf(errlogFatal, "%s: read error\n", record->name); recGblSetSevr(record, READ_ALARM, INVALID_ALARM); } return status; } /* calcout **********************************************************/ #ifndef EPICS_3_13 STATIC long s7plcFWInitRecordCalcout(calcoutRecord *record) { S7memPrivate_t *priv; int status; if (record->out.type != INST_IO) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordCalcout: illegal OUT field"); return S_db_badField; } priv = (S7memPrivate_t *)callocMustSucceed(1, sizeof(S7memPrivate_t), "s7plcFWInitRecordCalcout"); status = s7plcFWIoParse(record->name, record->out.value.instio.string, priv); if (status) { recGblRecordError(S_db_badField, record, "s7plcFWInitRecordCalcout: bad OUT field"); return S_db_badField; } assert(priv->station); switch (priv->dtype) { case epicsInt8T: case epicsUInt8T: case epicsInt16T: case epicsUInt16T: case epicsInt32T: case epicsUInt32T: case epicsFloat32T: case epicsFloat64T: break; default: errlogSevPrintf(errlogFatal, "s7plcFWInitRecordCalcout %s: illegal data type\n", record->name); return S_db_badField; } record->dpvt = priv; return 2; /* preserve whatever is in the VAL field */ } STATIC long s7plcFWWriteCalcout(calcoutRecord *record) { int status; S7memPrivate_t *priv = (S7memPrivate_t *)record->dpvt; epicsUInt8 uval8; epicsUInt16 uval16; epicsUInt32 uval32; epicsInt8 sval8; epicsInt16 sval16; epicsInt32 sval32; union {epicsFloat32 f; epicsUInt32 i; } val32; __extension__ union {epicsFloat64 f; epicsUInt64 i; } val64; if (!priv) { recGblSetSevr(record, UDF_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: not initialized\n", record->name); return -1; } assert(priv->station); val64.f = record->oval; switch (priv->dtype) { case epicsInt8T: sval8 = val64.f; if (val64.f > priv->hwHigh) sval8 = priv->hwHigh; if (val64.f < priv->hwLow) sval8 = priv->hwLow; s7plcFWDebugLog(2, "calcout %s: write 8bit %02x\n", record->name, sval8 & 0xff); status = s7plcFWWrite(priv->station, priv->offs, 1, &sval8); break; case epicsUInt8T: uval8 = val64.f; if (val64.f > priv->hwHigh) uval8 = priv->hwHigh; if (val64.f < priv->hwLow) uval8 = priv->hwLow; s7plcFWDebugLog(2, "calcout %s: write 8bit %02x\n", record->name, uval8 & 0xff); status = s7plcFWWrite(priv->station, priv->offs, 1, &uval8); break; case epicsInt16T: sval16 = val64.f; if (val64.f > priv->hwHigh) sval16 = priv->hwHigh; if (val64.f < priv->hwLow) sval16 = priv->hwLow; s7plcFWDebugLog(2, "calcout %s: write 16bit %04x\n", record->name, sval16 & 0xffff); status = s7plcFWWrite(priv->station, priv->offs, 2, &sval16); break; case epicsUInt16T: uval16 = val64.f; if (val64.f > priv->hwHigh) uval16 = priv->hwHigh; if (val64.f < priv->hwLow) uval16 = priv->hwLow; s7plcFWDebugLog(2, "calcout %s: write 16bit %04x\n", record->name, uval16 & 0xffff); status = s7plcFWWrite(priv->station, priv->offs, 2, &uval16); break; case epicsInt32T: sval32 = val64.f; if (val64.f > priv->hwHigh) sval32 = priv->hwHigh; if (val64.f < priv->hwLow) sval32 = priv->hwLow; s7plcFWDebugLog(2, "calcout %s: write 32bit %08x\n", record->name, sval32); status = s7plcFWWrite(priv->station, priv->offs, 4, &sval32); break; case epicsUInt32T: uval32 = val64.f; if (val64.f > priv->hwHigh) uval32 = priv->hwHigh; if (val64.f < priv->hwLow) uval32 = priv->hwLow; s7plcFWDebugLog(2, "calcout %s: write 32bit %08x\n", record->name, uval32); status = s7plcFWWrite(priv->station, priv->offs, 4, &uval32); break; case epicsFloat32T: val32.f = val64.f; s7plcFWDebugLog(2, "calcout %s: write 32bit %08x = %g\n", record->name, val32.i, val32.f); status = s7plcFWWrite(priv->station, priv->offs, 4, &val32); break; case epicsFloat64T: __extension__ s7plcFWDebugLog(2, "calcout %s: write 64bit " CONV64 " = %g\n", record->name, val64.i, val64.f); status = s7plcFWWrite(priv->station, priv->offs, 8, &val64); break; default: recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); errlogSevPrintf(errlogFatal, "%s: unexpected data type requested\n", record->name); return -1; } if (status == S_drv_noConn) { recGblSetSevr(record, COMM_ALARM, INVALID_ALARM); return 0; } if (status) { recGblSetSevr(record, WRITE_ALARM, INVALID_ALARM); } return status; } #endif