From 2fb0b0763dcc0b4ab14ef7348a5e3f2279a5826b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Jul 2014 18:13:28 -0500 Subject: [PATCH 01/25] Implement 64-bit database field types. Incorporates major reworking of the dbConvert.c file. if the 64-bit stuff gets rejected most of that should get pulled in anyway. --- src/ioc/db/dbAccess.c | 4 + src/ioc/db/dbChannel.c | 2 + src/ioc/db/dbConvert.c | 5220 ++++++------------------- src/ioc/db/dbFastLinkConv.c | 777 ++-- src/ioc/db/dbTest.c | 470 +-- src/ioc/db/db_convert.h | 12 +- src/ioc/db/menuFtype.dbd | 7 +- src/ioc/db/recGbl.c | 12 +- src/ioc/dbStatic/dbFldTypes.h | 6 + src/ioc/dbStatic/dbStaticLib.c | 249 +- src/ioc/dbStatic/dbStaticRun.c | 476 +-- src/libCom/cvtFast/cvtFast.c | 695 ++-- src/libCom/cvtFast/cvtFast.h | 111 +- src/libCom/misc/epicsStdlib.c | 8 +- src/libCom/osi/os/vxWorks/README | 3 - src/libCom/osi/os/vxWorks/osdStrtod.h | 6 +- src/libCom/test/Makefile | 5 + src/libCom/test/cvtFastTest.c | 457 +++ src/tools/DBD/Recfield.pm | 39 + 19 files changed, 3142 insertions(+), 5417 deletions(-) delete mode 100644 src/libCom/osi/os/vxWorks/README create mode 100644 src/libCom/test/cvtFastTest.c diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index d624fa5e4..97d2e8cc8 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -78,6 +78,8 @@ static short mapDBFToDBR[DBF_NTYPES] = { /* DBF_USHORT => */ DBR_USHORT, /* DBF_LONG => */ DBR_LONG, /* DBF_ULONG => */ DBR_ULONG, + /* DBF_INT64 => */ DBR_INT64, + /* DBF_UINT64 => */ DBR_UINT64, /* DBF_FLOAT => */ DBR_FLOAT, /* DBF_DOUBLE => */ DBR_DOUBLE, /* DBF_ENUM, => */ DBR_ENUM, @@ -693,6 +695,8 @@ long dbValueSize(short dbr_type) sizeof(epicsUInt16), /* USHORT */ sizeof(epicsInt32), /* LONG */ sizeof(epicsUInt32), /* ULONG */ + sizeof(epicsInt64), /* INT64 */ + sizeof(epicsUInt64), /* UINT64 */ sizeof(epicsFloat32), /* FLOAT */ sizeof(epicsFloat64), /* DOUBLE */ sizeof(epicsEnum16)}; /* ENUM */ diff --git a/src/ioc/db/dbChannel.c b/src/ioc/db/dbChannel.c index 6e08f3c19..11e6c2ab2 100644 --- a/src/ioc/db/dbChannel.c +++ b/src/ioc/db/dbChannel.c @@ -454,6 +454,8 @@ static short mapDBFToDBR[DBF_NTYPES] = /* DBF_USHORT => */DBR_USHORT, /* DBF_LONG => */DBR_LONG, /* DBF_ULONG => */DBR_ULONG, + /* DBF_INT64 => */DBR_INT64, + /* DBF_UINT64 => */DBR_UINT64, /* DBF_FLOAT => */DBR_FLOAT, /* DBF_DOUBLE => */DBR_DOUBLE, /* DBF_ENUM, => */DBR_ENUM, diff --git a/src/ioc/db/dbConvert.c b/src/ioc/db/dbConvert.c index 0fad81d5a..cd32ad5ea 100644 --- a/src/ioc/db/dbConvert.c +++ b/src/ioc/db/dbConvert.c @@ -1,22 +1,18 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbConvert.c */ /* * Original Author: Bob Dalesio - * Current Author: Marty Kraimer * Date: 11-7-90 */ #include -#include -#include #include #include #include @@ -25,6 +21,7 @@ #include "cvtFast.h" #include "dbDefs.h" #include "epicsConvert.h" +#include "epicsStdlib.h" #include "errlog.h" #include "errMdef.h" @@ -63,2202 +60,808 @@ static void copyNoConvert(const void *pfrom, #define COPYNOCONVERT(N, FROM, TO, NREQ, NO_ELEM, OFFSET) \ copyNoConvert(FROM, TO, (N)*(NREQ), (N)*(NO_ELEM), (N)*(OFFSET)) -/* DATABASE ACCESS GET CONVERSION SUPPORT */ +#define GET(typea, typeb) (const dbAddr *paddr, \ + void *pto, long nRequest, long no_elements, long offset) \ +{ \ + typea *psrc = (typea *) paddr->pfield; \ + typeb *pdst = (typeb *) pto; \ + \ + if (nRequest==1 && offset==0) { \ + *pdst = (typeb) *psrc; \ + return 0; \ + } \ + psrc += offset; \ + while (nRequest--) { \ + *pdst++ = (typeb) *psrc++; \ + if (++offset == no_elements) \ + psrc = (typea *) paddr->pfield; \ + } \ + return 0; \ +} + +#define GET_NOCONVERT(typea, typeb) (const dbAddr *paddr, \ + void *pto, long nRequest, long no_elements, long offset) \ +{ \ + if (nRequest==1 && offset==0) { \ + typea *psrc = (typea *) paddr->pfield; \ + typeb *pdst = (typeb *) pto; \ + \ + *pdst = (typeb) *psrc; \ + return 0; \ + } \ + COPYNOCONVERT(sizeof(typeb), paddr->pfield, pto, nRequest, no_elements, offset); \ + return 0; \ +} + +#define PUT(typea, typeb) (dbAddr *paddr, \ + const void *pfrom, long nRequest, long no_elements, long offset) \ +{ \ + const typea *psrc = (const typea *) pfrom; \ + typeb *pdst = (typeb *) paddr->pfield; \ + \ + if (nRequest==1 && offset==0) { \ + *pdst = (typeb) *psrc; \ + return 0; \ + } \ + pdst += offset; \ + while (nRequest--) { \ + *pdst++ = (typeb) *psrc++; \ + if (++offset == no_elements) \ + pdst = (typeb *) paddr->pfield; \ + } \ + return 0; \ +} + +#define PUT_NOCONVERT(typea, typeb) (dbAddr *paddr, \ + const void *pfrom, long nRequest, long no_elements, long offset) \ +{ \ + if (nRequest==1 && offset==0) { \ + const typea *psrc = (const typea *) pfrom; \ + typeb *pdst = (typeb *) paddr->pfield; \ + \ + *pdst = (typeb) *psrc; \ + return 0; \ + } \ + COPYNOCONVERT(sizeof(typeb), pfrom, paddr->pfield, nRequest, no_elements, offset); \ + return 0; \ +} + -static long getStringString ( - const dbAddr *paddr, +/* dbAccess Get conversion support routines */ + +static long getStringString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - char *pbuffer = (char *) pto; char *psrc = paddr->pfield; + char *pdst = (char *) pto; short size = paddr->field_size; short sizeto; /* always force result string to be null terminated*/ sizeto = size; - if (sizeto>=MAX_STRING_SIZE) sizeto = MAX_STRING_SIZE-1; + if (sizeto >= MAX_STRING_SIZE) + sizeto = MAX_STRING_SIZE - 1; if (nRequest==1 && offset==0) { - strncpy(pbuffer,psrc,sizeto); - pbuffer[sizeto] = 0; + strncpy(pdst, psrc, sizeto); + pdst[sizeto] = 0; return 0; } - psrc+= (size*offset); - while (nRequest) { - strncpy(pbuffer,psrc,sizeto); - pbuffer[sizeto] = 0; - pbuffer += MAX_STRING_SIZE; + psrc += size * offset; + while (nRequest--) { + strncpy(pdst, psrc, sizeto); + pdst[sizeto] = 0; + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = paddr->pfield; + psrc = paddr->pfield; else - psrc += size; - nRequest--; + psrc += size; } return 0; } -static long getStringChar( - const dbAddr *paddr, +static long getStringChar(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - char *pbuffer = (char *) pto; - char *psrc = (char *) paddr->pfield; - short value; + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsInt8 *pdst = pto; - if (nRequest==1 && offset==0) { - if (sscanf(psrc,"%hd",&value) == 1) { - *pbuffer = (char)value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseInt8(psrc, pdst++, 10, &end); + + if (status) + return status; } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (sscanf(psrc,"%hd",&value) == 1) { - *pbuffer = (char)value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; if (++offset == no_elements) psrc = paddr->pfield; else psrc += MAX_STRING_SIZE; - nRequest--; } return 0; } + +static long getStringUchar(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsUInt8 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseUInt8(psrc, pdst++, 10, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringShort(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsInt16 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseInt16(psrc, pdst++, 10, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringUshort(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsUInt16 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseUInt16(psrc, pdst++, 10, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringLong(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsInt32 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseInt32(psrc, pdst++, 10, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringUlong(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsUInt32 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseUInt32(psrc, pdst, 10, &end); + + if (status == S_stdlib_noConversion || + (!status && (*end == '.' || *end == 'e' || *end == 'E'))) { + /* + * Convert via double so numbers like 1.0e3 convert properly. + * db_access pretends unsigned long is double. + */ + epicsFloat64 dval; + + status = epicsParseFloat64(psrc, &dval, &end); + if (!status && 0 <= dval && dval <= ULONG_MAX) + *pdst = dval; + } + if (status) + return status; + pdst++; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringInt64(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsInt64 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseInt64(psrc, pdst++, 10, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringUInt64(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsUInt64 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseUInt64(psrc, pdst++, 0, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringFloat(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsFloat32 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseFloat32(psrc, pdst++, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + +static long getStringDouble(const dbAddr *paddr, + void *pto, long nRequest, long no_elements, long offset) +{ + char *psrc = (char *) paddr->pfield + MAX_STRING_SIZE * offset; + epicsFloat64 *pdst = pto; + + while (nRequest--) { + if (*psrc == 0) + *pdst++ = 0; + else { + char *end; + long status = epicsParseFloat64(psrc, pdst++, &end); + + if (status) + return status; + } + if (++offset == no_elements) + psrc = paddr->pfield; + else + psrc += MAX_STRING_SIZE; + } + return 0; +} + -static long getStringUchar( - const dbAddr *paddr, +static long getCharString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; char *psrc = (char *) paddr->pfield; - unsigned short value; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - if (sscanf(psrc,"%hu",&value) == 1) { - *pbuffer = (epicsUInt8)value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (sscanf(psrc,"%hu",&value) == 1) { - *pbuffer = (epicsUInt8)value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - char *psrc = (char *) paddr->pfield; - short value; - - if (nRequest==1 && offset==0) { - if (sscanf(psrc,"%hd",&value) == 1) { - *pbuffer = value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (sscanf(psrc,"%hd",&value) == 1) { - *pbuffer = value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - char *psrc = (char *) paddr->pfield; - unsigned short value; - - if (nRequest==1 && offset==0) { - if (sscanf(psrc,"%hu",&value) == 1) { - *pbuffer = value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (sscanf(psrc,"%hu",&value) == 1) { - *pbuffer = value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - char *psrc = (char *) paddr->pfield; - epicsInt32 value; - - if (nRequest==1 && offset==0) { - if (sscanf(psrc,"%d",&value) == 1) { - *pbuffer = value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (sscanf(psrc,"%d",&value) == 1) { - *pbuffer = value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - char *psrc = (char *) paddr->pfield; - double value; - - /*Convert to double first so that numbers like 1.0e3 convert properly*/ - /*Problem was old database access said to get unsigned long as double*/ - if (nRequest==1 && offset==0) { - if (epicsScanDouble(psrc, &value) == 1) { - *pbuffer = (epicsUInt32)value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (epicsScanDouble(psrc, &value) == 1) { - *pbuffer = (epicsUInt32)value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - char *psrc = (char *) paddr->pfield; - float value; - - if (nRequest==1 && offset==0) { - if (epicsScanFloat(psrc, &value) == 1) { - *pbuffer = value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (epicsScanFloat(psrc, &value) == 1) { - *pbuffer = value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - char *psrc = (char *) paddr->pfield; - double value; - - if (nRequest==1 && offset==0) { - if (epicsScanDouble(psrc, &value) == 1) { - *pbuffer = value; - return 0; - } else if (strlen(psrc) == 0) { - *pbuffer = 0.0; - return 0; - } else { - return(-1); - } - } - psrc += MAX_STRING_SIZE*offset; - while (nRequest) { - if (epicsScanDouble(psrc, &value) == 1) { - *pbuffer = value; - } else if (strlen(psrc) == 0) { - *pbuffer = 0.0; - } else { - return(-1); - } - pbuffer++; - if (++offset == no_elements) - psrc = paddr->pfield; - else - psrc += MAX_STRING_SIZE; - nRequest--; - } - return 0; -} - -static long getStringEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - return(getStringUshort(paddr,pto,nRequest,no_elements,offset)); -} - -static long getCharString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - cvtCharToString(*psrc,pbuffer); + cvtCharToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - cvtCharToString(*psrc,pbuffer); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtCharToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) psrc = (char *) paddr->pfield; else psrc++; - nRequest--; } return 0; } -static long getCharChar( - const dbAddr *paddr, +static long getCharChar(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - char *pbuffer = (char *) pto; char *psrc = (char *) paddr->pfield; + char *pdst = (char *) pto; if (paddr->pfldDes && paddr->pfldDes->field_type == DBF_STRING) { /* This is a DBF_STRING field being read as a long string. * The buffer we return must be zero-terminated. */ - pbuffer[--nRequest] = 0; - if (nRequest == 0) return 0; + pdst[--nRequest] = 0; + if (nRequest == 0) + return 0; } if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(char), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getCharUchar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - char *psrc = (char *) paddr->pfield; - - if (paddr->pfldDes && paddr->pfldDes->field_type == DBF_STRING) { - /* This is a DBF_STRING field being read as a long string. - * The buffer we return must be zero-terminated. - */ - pbuffer[--nRequest] = 0; - if (nRequest == 0) return 0; - } - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; + *pdst = *psrc; return 0; } COPYNOCONVERT(sizeof(char), paddr->pfield, pto, nRequest, no_elements, offset); return 0; } -static long getCharShort( - const dbAddr *paddr, +static long getCharUchar(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsInt16 *pbuffer = (epicsInt16 *) pto; char *psrc = (char *) paddr->pfield; + epicsUInt8 *pdst = (epicsUInt8 *) pto; + if (paddr->pfldDes && paddr->pfldDes->field_type == DBF_STRING) { + /* This is a DBF_STRING field being read as a long string. + * The buffer we return must be zero-terminated. + */ + pdst[--nRequest] = 0; + if (nRequest == 0) + return 0; + } if (nRequest==1 && offset==0) { - *pbuffer = *psrc; + *pdst = *psrc; return 0; } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } + COPYNOCONVERT(sizeof(char), paddr->pfield, pto, nRequest, no_elements, offset); return 0; } + +static long getCharShort GET(char, epicsInt16) +static long getCharUshort GET(char, epicsUInt16) +static long getCharLong GET(char, epicsInt32) +static long getCharUlong GET(char, epicsUInt32) +static long getCharInt64 GET(char, epicsInt64) +static long getCharUInt64 GET(char, epicsUInt64) +static long getCharFloat GET(char, epicsFloat32) +static long getCharDouble GET(char, epicsFloat64) +static long getCharEnum GET(char, epicsEnum16) -static long getCharUshort( - const dbAddr *paddr, +static long getUcharString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getCharLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getCharUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getCharFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getCharDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getCharEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - char *psrc = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - cvtUcharToString(*psrc,pbuffer); + cvtUcharToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - cvtUcharToString(*psrc,pbuffer); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtUcharToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; + psrc = (epicsUInt8 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return 0; } -static long getUcharChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - char *pbuffer = (char *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt8), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} +static long getUcharChar GET_NOCONVERT(epicsUInt8, char) +static long getUcharUchar GET_NOCONVERT(epicsUInt8, epicsUInt8) +static long getUcharShort GET(epicsUInt8, epicsInt16) +static long getUcharUshort GET(epicsUInt8, epicsUInt16) +static long getUcharLong GET(epicsUInt8, epicsInt32) +static long getUcharUlong GET(epicsUInt8, epicsUInt32) +static long getUcharInt64 GET(epicsUInt8, epicsInt64) +static long getUcharUInt64 GET(epicsUInt8, epicsUInt64) +static long getUcharFloat GET(epicsUInt8, epicsFloat32) +static long getUcharDouble GET(epicsUInt8, epicsFloat64) +static long getUcharEnum GET(epicsUInt8, epicsEnum16) -static long getUcharUchar( - const dbAddr *paddr, +static long getShortString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - if (nRequest==1 && offset==0) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt8), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getUcharShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUcharEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - epicsUInt8 *psrc = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getShortString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - cvtShortToString(*psrc,pbuffer); + cvtShortToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - cvtShortToString(*psrc,pbuffer); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtShortToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; + psrc = (epicsInt16 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return 0; } -static long getShortChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (char)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (char)*psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getShortChar GET(epicsInt16, char) +static long getShortUchar GET(epicsInt16, epicsUInt8) +static long getShortShort GET_NOCONVERT(epicsInt16, epicsInt16) +static long getShortUshort GET_NOCONVERT(epicsInt16, epicsUInt16) +static long getShortLong GET(epicsInt16, epicsInt32) +static long getShortUlong GET(epicsInt16, epicsUInt32) +static long getShortInt64 GET(epicsInt16, epicsInt64) +static long getShortUInt64 GET(epicsInt16, epicsUInt64) +static long getShortFloat GET(epicsInt16, epicsFloat32) +static long getShortDouble GET(epicsInt16, epicsFloat64) +static long getShortEnum GET(epicsInt16, epicsEnum16) -static long getShortUchar( - const dbAddr *paddr, +static long getUshortString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt8)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt8)*psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getShortShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsInt16 *pbuffer = (epicsInt16 *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt16), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getShortUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt16), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getShortLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getShortUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getShortFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getShortDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getShortEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - epicsInt16 *psrc = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUshortString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - cvtUshortToString(*psrc,pbuffer); + cvtUshortToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - cvtUshortToString(*psrc,pbuffer); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtUshortToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; + psrc = (epicsUInt16 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return 0; } -static long getUshortChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (char)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (char)*psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getUshortChar GET(epicsUInt16, char) +static long getUshortUchar GET(epicsUInt16, epicsUInt8) +static long getUshortShort GET_NOCONVERT(epicsUInt16, epicsInt16) +static long getUshortUshort GET_NOCONVERT(epicsUInt16, epicsUInt16) +static long getUshortLong GET(epicsUInt16, epicsInt32) +static long getUshortUlong GET(epicsUInt16, epicsUInt32) +static long getUshortInt64 GET(epicsUInt16, epicsInt64) +static long getUshortUInt64 GET(epicsUInt16, epicsUInt64) +static long getUshortFloat GET(epicsUInt16, epicsFloat32) +static long getUshortDouble GET(epicsUInt16, epicsFloat64) +static long getUshortEnum GET(epicsUInt16, epicsEnum16) -static long getUshortUchar( - const dbAddr *paddr, +static long getLongString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt8)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt8)*psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} -static long getUshortShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsInt16 *pbuffer = (epicsInt16 *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt16), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getUshortUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt16), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getUshortLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUshortUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUshortFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUshortDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUshortEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - epicsUInt16 *psrc = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getLongString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - cvtLongToString(*psrc,pbuffer); + cvtLongToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - cvtLongToString(*psrc,pbuffer); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtLongToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; + psrc = (epicsInt32 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return 0; } -static long getLongChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getLongChar GET(epicsInt32, char) +static long getLongUchar GET(epicsInt32, epicsUInt8) +static long getLongShort GET(epicsInt32, epicsInt16) +static long getLongUshort GET(epicsInt32, epicsUInt16) +static long getLongLong GET_NOCONVERT(epicsInt32, epicsInt32) +static long getLongUlong GET_NOCONVERT(epicsInt32, epicsUInt32) +static long getLongInt64 GET(epicsInt32, epicsInt64) +static long getLongUInt64 GET(epicsInt32, epicsUInt64) +static long getLongFloat GET(epicsInt32, epicsFloat32) +static long getLongDouble GET(epicsInt32, epicsFloat64) +static long getLongEnum GET(epicsInt32, epicsEnum16) -static long getLongUchar( - const dbAddr *paddr, +static long getUlongString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getLongShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getLongUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getLongLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsInt32 *pbuffer = (epicsInt32 *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt32), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getLongUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt32), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getLongFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (float)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (float)*psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getLongDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getLongEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - epicsInt32 *psrc = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUlongString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - cvtUlongToString(*psrc,pbuffer); + cvtUlongToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - cvtUlongToString(*psrc,pbuffer); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtUlongToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; + psrc = (epicsUInt32 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return 0; } -static long getUlongChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getUlongChar GET(epicsUInt32, char) +static long getUlongUchar GET(epicsUInt32, epicsUInt8) +static long getUlongShort GET(epicsUInt32, epicsInt16) +static long getUlongUshort GET(epicsUInt32, epicsUInt16) +static long getUlongLong GET_NOCONVERT(epicsUInt32, epicsInt32) +static long getUlongUlong GET_NOCONVERT(epicsUInt32, epicsUInt32) +static long getUlongInt64 GET(epicsUInt32, epicsInt64) +static long getUlongUInt64 GET(epicsUInt32, epicsUInt64) +static long getUlongFloat GET(epicsUInt32, epicsFloat32) +static long getUlongDouble GET(epicsUInt32, epicsFloat64) +static long getUlongEnum GET(epicsUInt32, epicsEnum16) -static long getUlongUchar( - const dbAddr *paddr, +static long getInt64String(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; + epicsInt64 *psrc = (epicsInt64 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - *pbuffer = *psrc; + cvtInt64ToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; + while (nRequest--) { + cvtInt64ToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; + psrc = (epicsInt64 *) paddr->pfield; + else + psrc++; } return 0; } -static long getUlongShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getInt64Char GET(epicsInt64, char) +static long getInt64Uchar GET(epicsInt64, epicsUInt8) +static long getInt64Short GET(epicsInt64, epicsInt16) +static long getInt64Ushort GET(epicsInt64, epicsUInt16) +static long getInt64Long GET(epicsInt64, epicsInt32) +static long getInt64Ulong GET(epicsInt64, epicsUInt32) +static long getInt64Int64 GET_NOCONVERT(epicsInt64, epicsInt64) +static long getInt64UInt64 GET_NOCONVERT(epicsInt64, epicsUInt64) +static long getInt64Float GET(epicsInt64, epicsFloat32) +static long getInt64Double GET(epicsInt64, epicsFloat64) +static long getInt64Enum GET(epicsInt64, epicsEnum16) -static long getUlongUshort( - const dbAddr *paddr, +static long getUInt64String(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; + epicsUInt64 *psrc = (epicsUInt64 *) paddr->pfield; + char *pdst = (char *) pto; if (nRequest==1 && offset==0) { - *pbuffer = *psrc; + cvtUInt64ToString(*psrc, pdst); return 0; } psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; + while (nRequest--) { + cvtUInt64ToString(*psrc, pdst); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; + psrc = (epicsUInt64 *) paddr->pfield; + else + psrc++; } return 0; } -static long getUlongLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsInt32 *pbuffer = (epicsInt32 *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt32), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} +static long getUInt64Char GET(epicsUInt64, char) +static long getUInt64Uchar GET(epicsUInt64, epicsUInt8) +static long getUInt64Short GET(epicsUInt64, epicsInt16) +static long getUInt64Ushort GET(epicsUInt64, epicsUInt16) +static long getUInt64Long GET(epicsUInt64, epicsInt32) +static long getUInt64Ulong GET(epicsUInt64, epicsUInt32) +static long getUInt64Int64 GET_NOCONVERT(epicsUInt64, epicsInt64) +static long getUInt64UInt64 GET_NOCONVERT(epicsUInt64, epicsUInt64) +static long getUInt64Float GET(epicsUInt64, epicsFloat32) +static long getUInt64Double GET(epicsUInt64, epicsFloat64) +static long getUInt64Enum GET(epicsUInt64, epicsEnum16) -static long getUlongUlong( - const dbAddr *paddr, +static long getFloatString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - if (nRequest==1 && offset==0) { - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt32), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getUlongFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (float)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (float)*psrc++; - if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUlongDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getUlongEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - epicsUInt32 *psrc = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - float *psrc = (float *) paddr->pfield; + epicsFloat32 *psrc = (epicsFloat32 *) paddr->pfield; + char *pdst = (char *) pto; long status = 0; - int precision = 6; + long precision = 6; struct rset *prset = 0; - if (paddr) prset = dbGetRset(paddr); - if (prset && (prset->get_precision)) - status = (*prset->get_precision)(paddr,&precision); + if (paddr) + prset = dbGetRset(paddr); + if (prset && prset->get_precision) + status = prset->get_precision(paddr, &precision); if (nRequest==1 && offset==0) { - cvtFloatToString(*psrc,pbuffer,precision); + cvtFloatToString(*psrc, pdst, precision); return(status); } psrc += offset; - while (nRequest) { - cvtFloatToString(*psrc,pbuffer,precision); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtFloatToString(*psrc, pdst, precision); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (float *) paddr->pfield; + psrc = (epicsFloat32 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return(status); } -static long getFloatChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (char)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (char)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getFloatChar GET(epicsFloat32, char) +static long getFloatUchar GET(epicsFloat32, epicsUInt8) +static long getFloatShort GET(epicsFloat32, epicsInt16) +static long getFloatUshort GET(epicsFloat32, epicsUInt16) +static long getFloatLong GET(epicsFloat32, epicsInt32) +static long getFloatUlong GET(epicsFloat32, epicsUInt32) +static long getFloatInt64 GET(epicsFloat32, epicsInt64) +static long getFloatUInt64 GET(epicsFloat32, epicsUInt64) +static long getFloatFloat GET_NOCONVERT(epicsFloat32, epicsFloat32) +static long getFloatDouble GET(epicsFloat32, epicsFloat64) +static long getFloatEnum GET(epicsFloat32, epicsEnum16) -static long getFloatUchar( - const dbAddr *paddr, +static long getDoubleString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt8)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt8)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsInt16)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsInt16)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt16)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt16)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsInt32)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsInt32)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt32)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt32)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - float *pbuffer = (float *) pto; - float *psrc = (float *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(float), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getFloatDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getFloatEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - float *psrc = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsEnum16)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsEnum16)*psrc++; - if (++offset == no_elements) - psrc = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - double *psrc = (double *) paddr->pfield; + epicsFloat64 *psrc = (epicsFloat64 *) paddr->pfield; + char *pdst = (char *) pto; long status = 0; - int precision = 6; + long precision = 6; struct rset *prset = 0; - if (paddr) prset = dbGetRset(paddr); - if (prset && (prset->get_precision)) - status = (*prset->get_precision)(paddr,&precision); + if (paddr) + prset = dbGetRset(paddr); + if (prset && prset->get_precision) + status = prset->get_precision(paddr, &precision); if (nRequest==1 && offset==0) { - cvtDoubleToString(*psrc,pbuffer,precision); + cvtDoubleToString(*psrc, pdst, precision); return(status); } psrc += offset; - while (nRequest) { - cvtDoubleToString(*psrc,pbuffer,precision); - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + cvtDoubleToString(*psrc, pdst, precision); + pdst += MAX_STRING_SIZE; if (++offset == no_elements) - psrc = (double *) paddr->pfield; + psrc = (epicsFloat64 *) paddr->pfield; else - psrc++; - nRequest--; + psrc++; } return(status); } -static long getDoubleChar( - const dbAddr *paddr, +static long getDoubleChar GET(epicsFloat64, char) +static long getDoubleUchar GET(epicsFloat64, epicsUInt8) +static long getDoubleShort GET(epicsFloat64, epicsInt16) +static long getDoubleUshort GET(epicsFloat64, epicsUInt16) +static long getDoubleLong GET(epicsFloat64, epicsInt32) +static long getDoubleUlong GET(epicsFloat64, epicsUInt32) +static long getDoubleInt64 GET(epicsFloat64, epicsInt64) +static long getDoubleUInt64 GET(epicsFloat64, epicsUInt64) + +static long getDoubleFloat(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - char *pbuffer = (char *) pto; - double *psrc = (double *) paddr->pfield; + epicsFloat64 *psrc = (epicsFloat64 *) paddr->pfield; + epicsFloat32 *pdst = (epicsFloat32 *) pto; if (nRequest==1 && offset==0) { - *pbuffer = (char)*psrc; + *pdst = epicsConvertDoubleToFloat(*psrc); return 0; } psrc += offset; - while (nRequest) { - *pbuffer++ = (char)*psrc++; + while (nRequest--) { + *pdst = epicsConvertDoubleToFloat(*psrc); + ++psrc; ++pdst; if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; + psrc = (epicsFloat64 *) paddr->pfield; } return 0; } + +static long getDoubleDouble GET_NOCONVERT(epicsFloat64, epicsFloat64) +static long getDoubleEnum GET(epicsFloat64, epicsEnum16) -static long getDoubleUchar( - const dbAddr *paddr, +static long getEnumString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt8)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt8)*psrc++; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsInt16)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsInt16)*psrc++; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt16)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt16)*psrc++; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsInt32)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsInt32)*psrc++; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt32)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt32)*psrc++; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = epicsConvertDoubleToFloat(*psrc); - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer = epicsConvertDoubleToFloat(*psrc); - ++psrc; ++pbuffer; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getDoubleDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - double *pbuffer = (double *) pto; - double *psrc = (double *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(double), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getDoubleEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - double *psrc = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsEnum16)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsEnum16)*psrc++; - if (++offset == no_elements) - psrc = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; + char *pdst = (char *) pto; struct rset *prset; long status; - if ((prset=dbGetRset(paddr)) && (prset->get_enum_str)) - return( (*prset->get_enum_str)(paddr,pbuffer) ); - status=S_db_noRSET; - recGblRecSupError(status,paddr,"dbGet","get_enum_str"); - return(S_db_badDbrtype); + prset = dbGetRset(paddr); + if (prset && prset->get_enum_str) + return prset->get_enum_str(paddr, pdst); + + status = S_db_noRSET; + recGblRecSupError(status, paddr, "dbGet", "get_enum_str"); + return S_db_badDbrtype; } -static long getEnumChar( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (char)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (char)*psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long getEnumChar GET(epicsEnum16, char) +static long getEnumUchar GET(epicsEnum16, epicsUInt8) +static long getEnumShort GET(epicsEnum16, epicsInt16) +static long getEnumUshort GET(epicsEnum16, epicsUInt16) +static long getEnumLong GET(epicsEnum16, epicsInt32) +static long getEnumUlong GET(epicsEnum16, epicsUInt32) +static long getEnumInt64 GET(epicsEnum16, epicsInt64) +static long getEnumUInt64 GET(epicsEnum16, epicsUInt64) +static long getEnumFloat GET(epicsEnum16, epicsFloat32) +static long getEnumDouble GET(epicsEnum16, epicsFloat64) +static long getEnumEnum GET_NOCONVERT(epicsEnum16, epicsEnum16) -static long getEnumUchar( - const dbAddr *paddr, +static long getMenuString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - epicsUInt8 *pbuffer = (epicsUInt8 *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = (epicsUInt8)*psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = (epicsUInt8)*psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumShort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt16 *pbuffer = (epicsInt16 *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumUshort( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt16 *pbuffer = (epicsUInt16 *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumLong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsInt32 *pbuffer = (epicsInt32 *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumUlong( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - epicsUInt32 *pbuffer = (epicsUInt32 *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumFloat( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - float *pbuffer = (float *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumDouble( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - double *pbuffer = (double *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pbuffer = *psrc; - return 0; - } - psrc += offset; - while (nRequest) { - *pbuffer++ = *psrc++; - if (++offset == no_elements) - psrc = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long getEnumEnum( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - epicsEnum16 *pbuffer = (epicsEnum16 *) pto; - epicsEnum16 *psrc = (epicsEnum16 *) paddr->pfield; - - *pbuffer = *psrc; - return 0; - } - COPYNOCONVERT(sizeof(epicsEnum16), paddr->pfield, pto, nRequest, no_elements, offset); - return 0; -} - -static long getMenuString( - const dbAddr *paddr, - void *pto, long nRequest, long no_elements, long offset) -{ - char *pbuffer = (char *) pto; + char *pdst = (char *) pto; dbFldDes *pdbFldDes = paddr->pfldDes; dbMenu *pdbMenu; char **papChoiceValue; @@ -2266,26 +869,25 @@ static long getMenuString( epicsEnum16 choice_ind= *((epicsEnum16*) paddr->pfield); if (no_elements!=1){ - recGblDbaddrError(S_db_onlyOne,paddr,"dbGet(getMenuString)"); + recGblDbaddrError(S_db_onlyOne, paddr, "dbGet(getMenuString)"); return(S_db_onlyOne); } if (!pdbFldDes - || !(pdbMenu = (dbMenu *)pdbFldDes->ftPvt) + || !(pdbMenu = (dbMenu *) pdbFldDes->ftPvt) || (choice_ind>=pdbMenu->nChoice) || !(papChoiceValue = pdbMenu->papChoiceValue) || !(pchoice=papChoiceValue[choice_ind])) { - recGblDbaddrError(S_db_badChoice,paddr,"dbGet(getMenuString)"); + recGblDbaddrError(S_db_badChoice, paddr, "dbGet(getMenuString)"); return(S_db_badChoice); } - strncpy(pbuffer,pchoice,MAX_STRING_SIZE); + strncpy(pdst, pchoice, MAX_STRING_SIZE); return 0; } -static long getDeviceString( - const dbAddr *paddr, +static long getDeviceString(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset) { - char *pbuffer = (char *) pto; + char *pdst = (char *) pto; dbFldDes *pdbFldDes = paddr->pfldDes; dbDeviceMenu *pdbDeviceMenu; char **papChoice; @@ -2293,2280 +895,804 @@ static long getDeviceString( epicsEnum16 choice_ind= *((epicsEnum16*) paddr->pfield); if (no_elements!=1){ - recGblDbaddrError(S_db_onlyOne,paddr,"dbGet(getDeviceString)"); + recGblDbaddrError(S_db_onlyOne, paddr, "dbGet(getDeviceString)"); return(S_db_onlyOne); } if (!pdbFldDes - || !(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt) + || !(pdbDeviceMenu = (dbDeviceMenu *) pdbFldDes->ftPvt) || (choice_ind>=pdbDeviceMenu->nChoice ) || !(papChoice = pdbDeviceMenu->papChoice) || !(pchoice=papChoice[choice_ind])) { - recGblDbaddrError(S_db_badChoice,paddr,"dbGet(getDeviceString)"); + recGblDbaddrError(S_db_badChoice, paddr, "dbGet(getDeviceString)"); return(S_db_badChoice); } - strncpy(pbuffer,pchoice,MAX_STRING_SIZE); + strncpy(pdst, pchoice, MAX_STRING_SIZE); return 0; } - -/* DATABASE ACCESS PUT CONVERSION SUPPORT */ -static long putStringString( - dbAddr *paddr, + +/* dbAccess put conversion support routines */ + +static long putStringString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - char *pdest = paddr->pfield; + const char *psrc = (const char *) pfrom; + char *pdst = paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - strncpy(pdest,pbuffer,size); - *(pdest+size-1) = 0; + strncpy(pdst, psrc, size); + *(pdst+size-1) = 0; return 0; } - pdest+= (size*offset); - while (nRequest) { - strncpy(pdest,pbuffer,size); - *(pdest+size-1) = 0; - pbuffer += MAX_STRING_SIZE; + pdst+= (size*offset); + while (nRequest--) { + strncpy(pdst, psrc, size); + pdst[size-1] = 0; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; + pdst = paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putStringChar( - dbAddr *paddr, +static long putStringChar(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - char *pdest = (char *) paddr->pfield; - short value; + const char *psrc = pfrom; + epicsInt8 *pdst = (epicsInt8 *) paddr->pfield + offset; - if (nRequest==1 && offset==0) { - if (sscanf(pbuffer,"%hd",&value) == 1) { - *pdest = (char)value; - return 0; - } - else return(-1); - } - pdest += offset; - while (nRequest) { - if (sscanf(pbuffer,"%hd",&value) == 1) { - *pdest = (char)value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; - if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; - } - return 0; -} - -static long putStringUchar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - unsigned short value; + while (nRequest--) { + char *end; + long status = epicsParseInt8(psrc, pdst++, 10, &end); - if (nRequest==1 && offset==0) { - if (sscanf(pbuffer,"%hu",&value) == 1) { - *pdest = (epicsUInt8)value; - return 0; - } - else return(-1); - } - pdest += offset; - while (nRequest) { - if (sscanf(pbuffer,"%hu",&value) == 1) { - *pdest = (epicsUInt8)value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + if (status) + return status; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; + pdst = paddr->pfield; } return 0; } -static long putStringShort( - dbAddr *paddr, +static long putStringUchar(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - short value; + const char *psrc = pfrom; + epicsUInt8 *pdst = (epicsUInt8 *) paddr->pfield + offset; - if (nRequest==1 && offset==0) { - if (sscanf(pbuffer,"%hd",&value) == 1) { - *pdest = value; - return 0; - } - else return(-1); - } - pdest += offset; - while (nRequest) { - if (sscanf(pbuffer,"%hd",&value) == 1) { - *pdest = value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + char *end; + long status = epicsParseUInt8(psrc, pdst++, 10, &end); + + if (status) + return status; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; + pdst = paddr->pfield; } return 0; } -static long putStringUshort( - dbAddr *paddr, +static long putStringShort(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - unsigned short value; + const char *psrc = pfrom; + epicsInt16 *pdst = (epicsInt16 *) paddr->pfield + offset; - if (nRequest==1 && offset==0) { - if (sscanf(pbuffer,"%hu",&value) == 1) { - *pdest = value; - return 0; - } - else return(-1); - } - pdest += offset; - while (nRequest) { - if (sscanf(pbuffer,"%hu",&value) == 1) { - *pdest = value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + char *end; + long status = epicsParseInt16(psrc, pdst++, 10, &end); + + if (status) + return status; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; + pdst = paddr->pfield; } return 0; } -static long putStringLong( - dbAddr *paddr, +static long putStringUshort(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - long value; + const char *psrc = pfrom; + epicsUInt16 *pdst = (epicsUInt16 *) paddr->pfield + offset; - if (nRequest==1 && offset==0) { - if (sscanf(pbuffer,"%ld",&value) == 1) { - *pdest = value; - return 0; - } - else return(-1); - } - pdest += offset; - while (nRequest) { - if (sscanf(pbuffer,"%ld",&value) == 1) { - *pdest = value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + char *end; + long status = epicsParseUInt16(psrc, pdst++, 10, &end); + + if (status) + return status; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; + pdst = paddr->pfield; } return 0; } -static long putStringUlong( - dbAddr *paddr, +static long putStringLong(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - double value; + const char *psrc = pfrom; + epicsInt32 *pdst = (epicsInt32 *) paddr->pfield + offset; - /*Convert to double first so that numbers like 1.0e3 convert properly*/ - /*Problem was old database access said to get unsigned long as double*/ - if (nRequest==1 && offset==0) { - if (epicsScanDouble(pbuffer, &value) == 1) { - *pdest = (epicsUInt32)value; - return 0; - } - else return(-1); - } - pdest += offset; - while (nRequest) { - if (epicsScanDouble(pbuffer, &value) == 1) { - *pdest = (epicsUInt32)value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + char *end; + long status = epicsParseInt32(psrc, pdst++, 10, &end); + + if (status) + return status; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; + pdst = paddr->pfield; } return 0; } -static long putStringFloat( - dbAddr *paddr, +static long putStringUlong(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - float *pdest = (float *) paddr->pfield; - float value; + const char *psrc = pfrom; + epicsUInt32 *pdst = (epicsUInt32 *) paddr->pfield + offset; - if (nRequest==1 && offset==0) { - if (epicsScanFloat(pbuffer, &value) == 1) { - *pdest = value; - return 0; - } else { - return(-1); + while (nRequest--) { + char *end; + long status = epicsParseUInt32(psrc, pdst, 10, &end); + + if (status == S_stdlib_noConversion || + (!status && (*end == '.' || *end == 'e' || *end == 'E'))) { + /* + * Convert via double so numbers like 1.0e3 convert properly. + * db_access pretends unsigned long is double. + */ + epicsFloat64 dval; + + status = epicsParseFloat64(psrc, &dval, &end); + if (!status && 0 <= dval && dval <= ULONG_MAX) + *pdst = dval; } - } - pdest += offset; - while (nRequest) { - if (epicsScanFloat(pbuffer, &value) == 1) { - *pdest = value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + if (status) + return status; + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; + pdst = paddr->pfield; else - pdest++; - nRequest--; + pdst++; } return 0; } -static long putStringDouble( - dbAddr *paddr, +static long putStringInt64(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - double *pdest = (double *) paddr->pfield; - double value; + const char *psrc = pfrom; + epicsInt64 *pdst = (epicsInt64 *) paddr->pfield + offset; - if (nRequest==1 && offset==0) { - if (epicsScanDouble(pbuffer, &value) == 1) { - *pdest = value; - return 0; - } else { - return(-1); - } - } - pdest += offset; - while (nRequest) { - if (epicsScanDouble(pbuffer, &value) == 1) { - *pdest = value; - } else { - return(-1); - } - pbuffer += MAX_STRING_SIZE; + while (nRequest--) { + char *end; + long status = epicsParseInt64(psrc, pdst++, 10, &end); + + if (status) + return status; + + psrc += MAX_STRING_SIZE; if (++offset == no_elements) - pdest = paddr->pfield; - else - pdest++; - nRequest--; + pdst = paddr->pfield; } return 0; } - -static long putStringEnum( - dbAddr *paddr, + +static long putStringUInt64(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - struct rset *prset; - epicsEnum16 *pfield = (epicsEnum16*) paddr->pfield; - long status; - unsigned int nchoices,ind; - int nargs,nchars; + const char *psrc = pfrom; + epicsUInt64 *pdst = (epicsUInt64 *) paddr->pfield + offset; + + while (nRequest--) { + char *end; + long status = epicsParseUInt64(psrc, pdst, 0, &end); + + if (status) + return status; + + psrc += MAX_STRING_SIZE; + if (++offset == no_elements) + pdst = paddr->pfield; + else + pdst++; + } + return 0; +} + +static long putStringFloat(dbAddr *paddr, + const void *pfrom, long nRequest, long no_elements, long offset) +{ + const char *psrc = pfrom; + epicsFloat32 *pdst = (epicsFloat32 *) paddr->pfield + offset; + + while (nRequest--) { + char *end; + long status = epicsParseFloat32(psrc, pdst++, &end); + + if (status) + return status; + psrc += MAX_STRING_SIZE; + if (++offset == no_elements) + pdst = paddr->pfield; + } + return 0; +} + +static long putStringDouble(dbAddr *paddr, + const void *pfrom, long nRequest, long no_elements, long offset) +{ + const char *psrc = pfrom; + epicsFloat64 *pdst = (epicsFloat64 *) paddr->pfield + offset; + + while (nRequest--) { + char *end; + long status = epicsParseFloat64(psrc, pdst++, &end); + + if (status) + return status; + psrc += MAX_STRING_SIZE; + if (++offset == no_elements) + pdst = paddr->pfield; + } + return 0; +} + +static long putStringEnum(dbAddr *paddr, + const void *pfrom, long nRequest, long no_elements, long offset) +{ + epicsEnum16 *pfield = paddr->pfield; + struct rset *prset = dbGetRset(paddr); + long status = S_db_noRSET; struct dbr_enumStrs enumStrs; - if ((prset=dbGetRset(paddr)) - && (prset->put_enum_str)) { - status = (*prset->put_enum_str)(paddr,pbuffer); - if (!status) return 0; - if (prset->get_enum_strs) { - status = (*prset->get_enum_strs)(paddr,&enumStrs); - if (!status) { - nchoices = enumStrs.no_str; - nargs = sscanf(pbuffer,"%u%n",&ind,&nchars); - if (nargs==1 && nchars==strlen(pbuffer) && indput_enum_str) { + recGblRecSupError(status, paddr, "dbPut(putStringEnum)", "put_enum_str"); + return status; + } + + status = prset->put_enum_str(paddr, pfrom); + if (!status) + return status; + + if (!prset->get_enum_strs) { + recGblRecSupError(status, paddr, "dbPut(putStringEnum)", "get_enum_strs"); + return status; + } + + status = prset->get_enum_strs(paddr, &enumStrs); + if (!status) { + epicsEnum16 val; + char *end; + + status = epicsParseUInt16(pfrom, &val, 10, &end); + if (!status && val < enumStrs.no_str) { + *pfield = val; + return 0; } - } else { - status=S_db_noRSET; + status = S_db_badChoice; } - if (status == S_db_noRSET) { - recGblRecSupError(status,paddr,"dbPutField","put_enum_str"); - } else { - recGblRecordError(status,(void *) paddr->precord,pbuffer); - } - return(status); + + recGblRecordError(status, paddr->precord, pfrom); + return status; } - -static long putStringMenu( - dbAddr *paddr, + +static long putStringMenu(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const char *pbuffer = (const char *) pfrom; - dbFldDes *pdbFldDes = paddr->pfldDes; - dbMenu *pdbMenu; - char **papChoiceValue; - char *pchoice; - epicsEnum16 *pfield = (epicsEnum16*) paddr->pfield; - unsigned int nChoice,ind; - int nargs,nchars; + dbFldDes *pdbFldDes = paddr->pfldDes; + epicsEnum16 *pfield = paddr->pfield; + dbMenu *pdbMenu; + char **pchoices, *pchoice; - if (no_elements!=1){ - recGblDbaddrError(S_db_onlyOne,paddr,"dbPut(putStringMenu)"); - return(S_db_onlyOne); + if (no_elements != 1) { + recGblDbaddrError(S_db_onlyOne, paddr, "dbPut(putStringMenu)"); + return S_db_onlyOne; } - if (pdbFldDes - && (pdbMenu = (dbMenu *)pdbFldDes->ftPvt) - && (papChoiceValue = pdbMenu->papChoiceValue)) { - nChoice = pdbMenu->nChoice; - for(ind=0; indftPvt) && + (pchoices = pdbMenu->papChoiceValue)) { + int i, nChoice = pdbMenu->nChoice; + epicsEnum16 val; + + for (i = 0; i < nChoice; i++) { + pchoice = pchoices[i]; + if (!pchoice) + continue; + if (strcmp(pchoice, pfrom) == 0) { + *pfield = i; return 0; } } - nargs = sscanf(pbuffer,"%u%n",&ind,&nchars); - if (nargs==1 && nchars==strlen(pbuffer) && indpfldDes; - dbDeviceMenu *pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; - char **papChoice; - char *pchoice; - epicsEnum16 *pfield = (epicsEnum16*) paddr->pfield; - unsigned int nChoice,ind; - int nargs,nchars; + dbFldDes *pdbFldDes = paddr->pfldDes; + dbDeviceMenu *pdbDeviceMenu = pdbFldDes->ftPvt; + epicsEnum16 *pfield = paddr->pfield; + char **pchoices, *pchoice; - if (no_elements!=1){ - recGblDbaddrError(S_db_onlyOne,paddr,"dbPut(putStringDevice)"); - return(S_db_onlyOne); + if (no_elements != 1) { + recGblDbaddrError(S_db_onlyOne, paddr, "dbPut(putStringDevice)"); + return S_db_onlyOne; } - if (pdbFldDes - && (pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt) - && (papChoice = pdbDeviceMenu->papChoice)) { - nChoice = pdbDeviceMenu->nChoice; - for(ind=0; indftPvt) && + (pchoices = pdbDeviceMenu->papChoice)) { + int i, nChoice = pdbDeviceMenu->nChoice; + epicsEnum16 val; + + for (i = 0; i < nChoice; i++) { + pchoice = pchoices[i]; + if (!pchoice) + continue; + if (strcmp(pchoice, pfrom) == 0) { + *pfield = i; return 0; } } - nargs = sscanf(pbuffer,"%u%n",&ind,&nchars); - if (nargs==1 && nchars==strlen(pbuffer) && indpfield; + const char *psrc = (const char *) pfrom; + char *pdst = (char *) paddr->pfield; + short size = paddr->field_size; + + if (nRequest==1 && offset==0) { + cvtCharToString(*psrc, pdst); + return 0; + } + pdst += (size*offset); + while (nRequest--) { + cvtCharToString(*psrc, pdst); + psrc++; + if (++offset == no_elements) + pdst = paddr->pfield; + else + pdst += size; + } + return 0; +} + +static long putCharChar PUT_NOCONVERT(char, char) +static long putCharUchar PUT_NOCONVERT(char, epicsUInt8) +static long putCharShort PUT(char, epicsInt16) +static long putCharUshort PUT(char, epicsUInt16) +static long putCharLong PUT(char, epicsInt32) +static long putCharUlong PUT(char, epicsUInt32) +static long putCharInt64 PUT(char, epicsInt64) +static long putCharUInt64 PUT(char, epicsUInt64) +static long putCharFloat PUT(char, epicsFloat32) +static long putCharDouble PUT(char, epicsFloat64) +static long putCharEnum PUT(char, epicsEnum16) + +static long putUcharString(dbAddr *paddr, + const void *pfrom, long nRequest, long no_elements, long offset) +{ + const epicsUInt8 *psrc = (const epicsUInt8 *) pfrom; + char *pdst = (char *) paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - cvtCharToString(*pbuffer,pdest); + cvtUcharToString(*psrc, pdst); return 0; } - pdest += (size*offset); - while (nRequest) { - cvtCharToString(*pbuffer,pdest); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtUcharToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = paddr->pfield; + pdst = paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putCharChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const char *pbuffer = (const char *) pfrom; - char *pdest = (char *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(char), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} +static long putUcharChar PUT_NOCONVERT(epicsUInt8, char) +static long putUcharUchar PUT_NOCONVERT(epicsUInt8, epicsUInt8) +static long putUcharShort PUT(epicsUInt8, epicsInt16) +static long putUcharUshort PUT(epicsUInt8, epicsUInt16) +static long putUcharLong PUT(epicsUInt8, epicsInt32) +static long putUcharUlong PUT(epicsUInt8, epicsUInt32) +static long putUcharInt64 PUT(epicsUInt8, epicsInt64) +static long putUcharUInt64 PUT(epicsUInt8, epicsUInt64) +static long putUcharFloat PUT(epicsUInt8, epicsFloat32) +static long putUcharDouble PUT(epicsUInt8, epicsFloat64) +static long putUcharEnum PUT(epicsUInt8, epicsEnum16) -static long putCharUchar( - dbAddr *paddr, +static long putShortString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - if (nRequest==1 && offset==0) { - const char *pbuffer = (const char *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt8), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putCharShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putCharUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putCharLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putCharUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putCharFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putCharDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putCharEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const char *pbuffer = (const char *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsInt16 *psrc = (const epicsInt16 *) pfrom; + char *pdst = (char *) paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - cvtUcharToString(*pbuffer,pdest); + cvtShortToString(*psrc, pdst); return 0; } - pdest += (size*offset); - while (nRequest) { - cvtUcharToString(*pbuffer,pdest); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtShortToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putUcharChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - char *pdest = (char *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt8), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} +static long putShortChar PUT(epicsInt16, char) +static long putShortUchar PUT(epicsInt16, epicsUInt8) +static long putShortShort PUT_NOCONVERT(epicsInt16, epicsInt16) +static long putShortUshort PUT_NOCONVERT(epicsInt16, epicsUInt16) +static long putShortLong PUT(epicsInt16, epicsInt32) +static long putShortUlong PUT(epicsInt16, epicsUInt32) +static long putShortInt64 PUT(epicsInt16, epicsInt64) +static long putShortUInt64 PUT(epicsInt16, epicsUInt64) +static long putShortFloat PUT(epicsInt16, epicsFloat32) +static long putShortDouble PUT(epicsInt16, epicsFloat64) +static long putShortEnum PUT(epicsInt16, epicsEnum16) -static long putUcharUchar( - dbAddr *paddr, +static long putUshortString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - if (nRequest==1 && offset==0) { - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt8), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putUcharShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUcharEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt8 *pbuffer = (const epicsUInt8 *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putShortString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsUInt16 *psrc = (const epicsUInt16 *) pfrom; + char *pdst = (char *) paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - cvtShortToString(*pbuffer,pdest); + cvtUshortToString(*psrc, pdst); return 0; } - pdest += (size*offset); - while (nRequest) { - cvtShortToString(*pbuffer,pdest); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtUshortToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putShortChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - char *pdest = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (char) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (char) *pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; - } - return 0; -} +static long putUshortChar PUT(epicsUInt16, char) +static long putUshortUchar PUT(epicsUInt16, epicsUInt8) +static long putUshortShort PUT_NOCONVERT(epicsUInt16, epicsInt16) +static long putUshortUshort PUT_NOCONVERT(epicsUInt16, epicsUInt16) +static long putUshortLong PUT(epicsUInt16, epicsInt32) +static long putUshortUlong PUT(epicsUInt16, epicsUInt32) +static long putUshortInt64 PUT(epicsUInt16, epicsInt64) +static long putUshortUInt64 PUT(epicsUInt16, epicsUInt64) +static long putUshortFloat PUT(epicsUInt16, epicsFloat32) +static long putUshortDouble PUT(epicsUInt16, epicsFloat64) +static long putUshortEnum PUT(epicsUInt16, epicsEnum16) -static long putShortUchar( - dbAddr *paddr, +static long putLongString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt8) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt8) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putShortShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt16), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putShortUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt16), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putShortLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putShortUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putShortFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putShortDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putShortEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt16 *pbuffer = (const epicsInt16 *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUshortString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsInt32 *psrc = (const epicsInt32 *) pfrom; + char *pdst = (char *) paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - cvtUshortToString(*pbuffer,pdest); + cvtLongToString(*psrc, pdst); return 0; } - pdest += (size*offset); - while (nRequest) { - cvtUshortToString(*pbuffer,pdest); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtLongToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putUshortChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - char *pdest = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (char) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (char) *pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; - } - return 0; -} +static long putLongChar PUT(epicsInt32, char) +static long putLongUchar PUT(epicsInt32, epicsUInt8) +static long putLongShort PUT(epicsInt32, epicsInt16) +static long putLongUshort PUT(epicsInt32, epicsUInt16) +static long putLongLong PUT_NOCONVERT(epicsInt32, epicsInt32) +static long putLongUlong PUT_NOCONVERT(epicsInt32, epicsUInt32) +static long putLongInt64 PUT(epicsInt32, epicsInt64) +static long putLongUInt64 PUT(epicsInt32, epicsUInt64) +static long putLongFloat PUT(epicsInt32, epicsFloat32) +static long putLongDouble PUT(epicsInt32, epicsFloat64) +static long putLongEnum PUT(epicsInt32, epicsEnum16) -static long putUshortUchar( - dbAddr *paddr, +static long putUlongString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt8) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt8) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUshortShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt16), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putUshortUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt16), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putUshortLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUshortUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUshortFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUshortDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUshortEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt16 *pbuffer = (const epicsUInt16 *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putLongString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsUInt32 *psrc = (const epicsUInt32 *) pfrom; + char *pdst = (char *) paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - cvtLongToString(*pbuffer,pdest); + cvtUlongToString(*psrc, pdst); return 0; } - pdest += (size*offset); - while (nRequest) { - cvtLongToString(*pbuffer,pdest); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtUlongToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putLongChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - char *pdest = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; - } - return 0; -} +static long putUlongChar PUT(epicsUInt32, char) +static long putUlongUchar PUT(epicsUInt32, epicsUInt8) +static long putUlongShort PUT(epicsUInt32, epicsInt16) +static long putUlongUshort PUT(epicsUInt32, epicsUInt16) +static long putUlongLong PUT_NOCONVERT(epicsUInt32, epicsInt32) +static long putUlongUlong PUT_NOCONVERT(epicsUInt32, epicsUInt32) +static long putUlongInt64 PUT(epicsUInt32, epicsInt64) +static long putUlongUInt64 PUT(epicsUInt32, epicsUInt64) +static long putUlongFloat PUT(epicsUInt32, epicsFloat32) +static long putUlongDouble PUT(epicsUInt32, epicsFloat64) +static long putUlongEnum PUT(epicsUInt32, epicsEnum16) -static long putLongUchar( - dbAddr *paddr, +static long putInt64String(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; + const epicsInt64 *psrc = (const epicsInt64 *) pfrom; + char *pdst = (char *) paddr->pfield; + short size=paddr->field_size; + if (nRequest==1 && offset==0) { - *pdest = *pbuffer; + cvtInt64ToString(*psrc, pdst); return 0; } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtInt64ToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putLongShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putLongUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putLongLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt32), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putLongUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsInt32), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putLongFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (float) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (float) *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putLongDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putLongEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsInt32 *pbuffer = (const epicsInt32 *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUlongString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - char *pdest = (char *) paddr->pfield; - short size = paddr->field_size; - - - if (nRequest==1 && offset==0) { - cvtUlongToString(*pbuffer,pdest); - return 0; - } - pdest += (size*offset); - while (nRequest) { - cvtUlongToString(*pbuffer,pdest); - pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putUlongChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - char *pdest = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; - } - return 0; -} +static long putInt64Char PUT(epicsInt64, char) +static long putInt64Uchar PUT(epicsInt64, epicsUInt8) +static long putInt64Short PUT(epicsInt64, epicsInt16) +static long putInt64Ushort PUT(epicsInt64, epicsUInt16) +static long putInt64Long PUT(epicsInt64, epicsInt32) +static long putInt64Ulong PUT(epicsInt64, epicsUInt32) +static long putInt64Int64 PUT_NOCONVERT(epicsInt64, epicsInt64) +static long putInt64UInt64 PUT_NOCONVERT(epicsInt64, epicsUInt64) +static long putInt64Float PUT(epicsInt64, epicsFloat32) +static long putInt64Double PUT(epicsInt64, epicsFloat64) +static long putInt64Enum PUT(epicsInt64, epicsEnum16) -static long putUlongUchar( - dbAddr *paddr, +static long putUInt64String(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; + const epicsUInt64 *psrc = (const epicsUInt64 *) pfrom; + char *pdst = (char *) paddr->pfield; + short size=paddr->field_size; + if (nRequest==1 && offset==0) { - *pdest = *pbuffer; + cvtUlongToString(*psrc, pdst); return 0; } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtUlongToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; + pdst = (char *) paddr->pfield; + else + pdst += size; } return 0; } -static long putUlongShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} +static long putUInt64Char PUT(epicsUInt64, char) +static long putUInt64Uchar PUT(epicsUInt64, epicsUInt8) +static long putUInt64Short PUT(epicsUInt64, epicsInt16) +static long putUInt64Ushort PUT(epicsUInt64, epicsUInt16) +static long putUInt64Long PUT(epicsUInt64, epicsInt32) +static long putUInt64Ulong PUT(epicsUInt64, epicsUInt32) +static long putUInt64Int64 PUT_NOCONVERT(epicsUInt64, epicsInt64) +static long putUInt64UInt64 PUT_NOCONVERT(epicsUInt64, epicsUInt64) +static long putUInt64Float PUT(epicsUInt64, epicsFloat32) +static long putUInt64Double PUT(epicsUInt64, epicsFloat64) +static long putUInt64Enum PUT(epicsUInt64, epicsEnum16) -static long putUlongUshort( - dbAddr *paddr, +static long putFloatString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUlongLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt32), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putUlongUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsUInt32), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putUlongFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (float) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (float) *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUlongDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putUlongEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsUInt32 *pbuffer = (const epicsUInt32 *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsFloat32 *psrc = (const epicsFloat32 *) pfrom; + char *pdst = (char *) paddr->pfield; long status = 0; - int precision = 6; - struct rset *prset = dbGetRset(paddr); + long precision = 6; + struct rset *prset = 0; short size = paddr->field_size; - if (prset && (prset->get_precision)) - status = (*prset->get_precision)(paddr,&precision); + if (paddr) + prset = dbGetRset(paddr); + if (prset && prset->get_precision) + status = prset->get_precision(paddr, &precision); if (nRequest==1 && offset==0) { - cvtFloatToString(*pbuffer,pdest,precision); + cvtFloatToString(*psrc, pdst, precision); return(status); } - pdest += (size*offset); - while (nRequest) { - cvtFloatToString(*pbuffer,pdest,precision); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtFloatToString(*psrc, pdst, precision); + psrc++; if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return(status); } -static long putFloatChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - char *pdest = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (char) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (char) *pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; - } - return 0; -} +static long putFloatChar PUT(epicsFloat32, char) +static long putFloatUchar PUT(epicsFloat32, epicsUInt8) +static long putFloatShort PUT(epicsFloat32, epicsInt16) +static long putFloatUshort PUT(epicsFloat32, epicsUInt16) +static long putFloatLong PUT(epicsFloat32, epicsInt32) +static long putFloatUlong PUT(epicsFloat32, epicsUInt32) +static long putFloatInt64 PUT(epicsFloat32, epicsInt64) +static long putFloatUInt64 PUT(epicsFloat32, epicsUInt64) +static long putFloatFloat PUT_NOCONVERT(epicsFloat32, epicsFloat32) +static long putFloatDouble PUT(epicsFloat32, epicsFloat64) +static long putFloatEnum PUT(epicsFloat32, epicsEnum16) -static long putFloatUchar( - dbAddr *paddr, +static long putDoubleString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const float *pbuffer = (const float *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt8) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt8) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsInt16) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsInt16) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt16) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt16) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsInt32) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsInt32) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt32) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt32) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const float *pbuffer = (const float *) pfrom; - float *pdest = (float *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(float), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putFloatDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putFloatEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const float *pbuffer = (const float *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsEnum16) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsEnum16) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsFloat64 *psrc = (const epicsFloat64 *) pfrom; + char *pdst = (char *) paddr->pfield; long status = 0; - int precision = 6; - struct rset *prset = dbGetRset(paddr); + long precision = 6; + struct rset *prset = 0; short size = paddr->field_size; - if (prset && (prset->get_precision)) - status = (*prset->get_precision)(paddr,&precision); + if (paddr) + prset = dbGetRset(paddr); + if (prset && prset->get_precision) + status = prset->get_precision(paddr, &precision); if (nRequest==1 && offset==0) { - cvtDoubleToString(*pbuffer,pdest,precision); - return(status); + cvtDoubleToString(*psrc, pdst, precision); + return status; } - pdest += (size*offset); - while (nRequest) { - cvtDoubleToString(*pbuffer,pdest,precision); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtDoubleToString(*psrc, pdst, precision); + psrc++; if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } - return(status); + return status; } -static long putDoubleChar( - dbAddr *paddr, +static long putDoubleChar PUT(epicsFloat64, char) +static long putDoubleUchar PUT(epicsFloat64, epicsUInt8) +static long putDoubleShort PUT(epicsFloat64, epicsInt16) +static long putDoubleUshort PUT(epicsFloat64, epicsUInt16) +static long putDoubleLong PUT(epicsFloat64, epicsInt32) +static long putDoubleUlong PUT(epicsFloat64, epicsUInt32) +static long putDoubleInt64 PUT(epicsFloat64, epicsInt64) +static long putDoubleUInt64 PUT(epicsFloat64, epicsUInt64) + +static long putDoubleFloat(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const double *pbuffer = (const double *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsFloat64 *psrc = (const epicsFloat64 *) pfrom; + epicsFloat32 *pdst = (epicsFloat32 *) paddr->pfield; if (nRequest==1 && offset==0) { - *pdest = (char) *pbuffer; + *pdst = epicsConvertDoubleToFloat(*psrc); return 0; } - pdest += offset; - while (nRequest) { - *pdest++ = (char) *pbuffer++; + pdst += offset; + while (nRequest--) { + *pdst++ = epicsConvertDoubleToFloat(*psrc++); if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; + pdst = (epicsFloat32 *) paddr->pfield; } return 0; } + +static long putDoubleDouble PUT_NOCONVERT(epicsFloat64, epicsFloat64) +static long putDoubleEnum PUT(epicsFloat64, epicsEnum16) -static long putDoubleUchar( - dbAddr *paddr, +static long putEnumString(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset) { - const double *pbuffer = (const double *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt8) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt8) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsInt16) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsInt16) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt16) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt16) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsInt32) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsInt32) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt32) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt32) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = epicsConvertDoubleToFloat(*pbuffer); - return 0; - } - pdest += offset; - while (nRequest) { - *pdest = epicsConvertDoubleToFloat(*pbuffer); - ++pbuffer; ++pdest; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putDoubleDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const double *pbuffer = (const double *) pfrom; - double *pdest = (double *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(double), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} - -static long putDoubleEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const double *pbuffer = (const double *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsEnum16) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsEnum16) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsEnum16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumString( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - char *pdest = (char *) paddr->pfield; + const epicsEnum16 *psrc = (const epicsEnum16 *) pfrom; + char *pdst = (char *) paddr->pfield; short size = paddr->field_size; if (nRequest==1 && offset==0) { - cvtUshortToString(*pbuffer,pdest); + cvtUshortToString(*psrc, pdst); return 0; } - pdest += (size*offset); - while (nRequest) { - cvtUshortToString(*pbuffer,pdest); - pbuffer++; + pdst += (size*offset); + while (nRequest--) { + cvtUshortToString(*psrc, pdst); + psrc++; if (++offset == no_elements) - pdest = (char *) paddr->pfield; + pdst = (char *) paddr->pfield; else - pdest += size; - nRequest--; + pdst += size; } return 0; } -static long putEnumChar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - char *pdest = (char *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (char) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (char) *pbuffer++; - if (++offset == no_elements) - pdest = (char *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumUchar( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - epicsUInt8 *pdest = (epicsUInt8 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = (epicsUInt8) *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = (epicsUInt8) *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt8 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumShort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - epicsInt16 *pdest = (epicsInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumUshort( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - epicsUInt16 *pdest = (epicsUInt16 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt16 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumLong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - epicsInt32 *pdest = (epicsInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumUlong( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - epicsUInt32 *pdest = (epicsUInt32 *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (epicsUInt32 *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumFloat( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - float *pdest = (float *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (float *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumDouble( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - double *pdest = (double *) paddr->pfield; - - if (nRequest==1 && offset==0) { - *pdest = *pbuffer; - return 0; - } - pdest += offset; - while (nRequest) { - *pdest++ = *pbuffer++; - if (++offset == no_elements) - pdest = (double *) paddr->pfield; - nRequest--; - } - return 0; -} - -static long putEnumEnum( - dbAddr *paddr, - const void *pfrom, long nRequest, long no_elements, long offset) -{ - if (nRequest==1 && offset==0) { - const epicsEnum16 *pbuffer = (const epicsEnum16 *) pfrom; - epicsEnum16 *pdest = (epicsEnum16 *) paddr->pfield; - - *pdest = *pbuffer; - return 0; - } - COPYNOCONVERT(sizeof(epicsEnum16), pfrom, paddr->pfield, nRequest, no_elements, offset); - return 0; -} +static long putEnumChar PUT(epicsEnum16, char) +static long putEnumUchar PUT(epicsEnum16, epicsUInt8) +static long putEnumShort PUT(epicsEnum16, epicsInt16) +static long putEnumUshort PUT(epicsEnum16, epicsUInt16) +static long putEnumLong PUT(epicsEnum16, epicsInt32) +static long putEnumUlong PUT(epicsEnum16, epicsUInt32) +static long putEnumInt64 PUT(epicsEnum16, epicsInt64) +static long putEnumUInt64 PUT(epicsEnum16, epicsUInt64) +static long putEnumFloat PUT(epicsEnum16, epicsFloat32) +static long putEnumDouble PUT(epicsEnum16, epicsFloat64) +static long putEnumEnum PUT_NOCONVERT(epicsEnum16, epicsEnum16) /* This is the table of routines for converting database fields */ /* the rows represent the field type of the database field */ @@ -4574,47 +1700,68 @@ static long putEnumEnum( /* buffer types are******************************************************** DBR_STRING, DBR_CHR, DBR_UCHAR, DBR_SHORT, DBR_USHORT, - DBR_LONG, DBR_ULONG, DBR_FLOAT, DBR_DOUBLE, DBR_ENUM + DBR_LONG, DBR_ULONG, DBR_INT64, DBR_UINT64, + DBR_FLOAT, DBR_DOUBLE, DBR_ENUM ***************************************************************************/ epicsShareDef GETCONVERTFUNC dbGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1] = { /* source is a DBF_STRING */ {getStringString, getStringChar, getStringUchar, getStringShort, getStringUshort, - getStringLong, getStringUlong, getStringFloat, getStringDouble, getStringEnum}, + getStringLong, getStringUlong, getStringInt64, getStringUInt64, + getStringFloat, getStringDouble, getStringUshort}, /* source is a DBF_CHAR */ {getCharString, getCharChar, getCharUchar, getCharShort, getCharUshort, - getCharLong, getCharUlong, getCharFloat, getCharDouble, getCharEnum}, + getCharLong, getCharUlong, getCharInt64, getCharUInt64, + getCharFloat, getCharDouble, getCharEnum}, /* source is a DBF_UCHAR */ {getUcharString, getUcharChar, getUcharUchar, getUcharShort, getUcharUshort, - getUcharLong, getUcharUlong, getUcharFloat, getUcharDouble, getUcharEnum}, + getUcharLong, getUcharUlong, getUcharInt64, getUcharUInt64, + getUcharFloat, getUcharDouble, getUcharEnum}, /* source is a DBF_SHORT */ {getShortString, getShortChar, getShortUchar, getShortShort, getShortUshort, - getShortLong, getShortUlong, getShortFloat, getShortDouble, getShortEnum}, + getShortLong, getShortUlong, getShortInt64, getShortUInt64, + getShortFloat, getShortDouble, getShortEnum}, /* source is a DBF_USHORT */ {getUshortString, getUshortChar, getUshortUchar, getUshortShort, getUshortUshort, - getUshortLong, getUshortUlong, getUshortFloat, getUshortDouble, getUshortEnum}, -/* source is a DBF_LONG */ + getUshortLong, getUshortUlong, getUshortInt64, getUshortUInt64, + getUshortFloat, getUshortDouble, getUshortEnum}, +/* source is a DBF_LONG */ {getLongString, getLongChar, getLongUchar, getLongShort, getLongUshort, - getLongLong, getLongUlong, getLongFloat, getLongDouble, getLongEnum}, + getLongLong, getLongUlong, getLongInt64, getLongUInt64, + getLongFloat, getLongDouble, getLongEnum}, /* source is a DBF_ULONG */ {getUlongString, getUlongChar, getUlongUchar, getUlongShort, getUlongUshort, - getUlongLong, getUlongUlong, getUlongFloat, getUlongDouble, getUlongEnum}, + getUlongLong, getUlongUlong, getUlongInt64, getUlongUInt64, + getUlongFloat, getUlongDouble, getUlongEnum}, +/* source is a DBF_INT64 */ +{getInt64String, getInt64Char, getInt64Uchar, getInt64Short, getInt64Ushort, + getInt64Long, getInt64Ulong, getInt64Int64, getInt64UInt64, + getInt64Float, getInt64Double, getInt64Enum}, +/* source is a DBF_UINT64 */ +{getUInt64String, getUInt64Char, getUInt64Uchar, getUInt64Short, getUInt64Ushort, + getUInt64Long, getUInt64Ulong, getUInt64Int64, getUInt64UInt64, + getUInt64Float, getUInt64Double, getUInt64Enum}, /* source is a DBF_FLOAT */ {getFloatString, getFloatChar, getFloatUchar, getFloatShort, getFloatUshort, - getFloatLong, getFloatUlong, getFloatFloat, getFloatDouble, getFloatEnum}, + getFloatLong, getFloatUlong, getFloatInt64, getFloatUInt64, + getFloatFloat, getFloatDouble, getFloatEnum}, /* source is a DBF_DOUBLE */ {getDoubleString, getDoubleChar, getDoubleUchar, getDoubleShort, getDoubleUshort, - getDoubleLong, getDoubleUlong, getDoubleFloat, getDoubleDouble, getDoubleEnum}, -/* source is a DBF_ENUM */ + getDoubleLong, getDoubleUlong, getDoubleInt64, getDoubleUInt64, + getDoubleFloat, getDoubleDouble, getDoubleEnum}, +/* source is a DBF_ENUM */ {getEnumString, getEnumChar, getEnumUchar, getEnumShort, getEnumUshort, - getEnumLong, getEnumUlong, getEnumFloat, getEnumDouble, getEnumEnum}, -/* source is a DBF_MENU */ + getEnumLong, getEnumUlong, getEnumInt64, getEnumUInt64, + getEnumFloat, getEnumDouble, getEnumEnum}, +/* source is a DBF_MENU */ {getMenuString, getEnumChar, getEnumUchar, getEnumShort, getEnumUshort, - getEnumLong, getEnumUlong, getEnumFloat, getEnumDouble, getEnumEnum}, -/* source is a DBF_DEVICE */ -{getDeviceString,getEnumChar, getEnumUchar, getEnumShort, getEnumUshort, - getEnumLong, getEnumUlong, getEnumFloat, getEnumDouble, getEnumEnum}, + getEnumLong, getEnumUlong, getEnumInt64, getEnumUInt64, + getEnumFloat, getEnumDouble, getEnumEnum}, +/* source is a DBF_DEVICE */ +{getDeviceString, getEnumChar, getEnumUchar, getEnumShort, getEnumUshort, + getEnumLong, getEnumUlong, getEnumInt64, getEnumUInt64, + getEnumFloat, getEnumDouble, getEnumEnum}, }; /* This is the table of routines for converting database fields */ @@ -4623,49 +1770,70 @@ epicsShareDef GETCONVERTFUNC dbGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1] = { /* field types are******************************************************** DBF_STRING, DBF_CHAR, DBF_UCHAR, DBF_SHORT, DBF_USHORT, - DBF_LONG, DBF_ULONG, DBF_FLOAT, DBF_DOUBLE, DBF_ENUM + DBF_LONG, DBF_ULONG, DBF_INT64, DBF_UINT64, + DBF_FLOAT, DBF_DOUBLE, DBF_ENUM DBF_MENU, DBF_DEVICE ***************************************************************************/ epicsShareDef PUTCONVERTFUNC dbPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1] = { /* source is a DBR_STRING */ {putStringString, putStringChar, putStringUchar, putStringShort, putStringUshort, - putStringLong, putStringUlong, putStringFloat, putStringDouble, putStringEnum, - putStringMenu,putStringDevice}, -/* source is a DBR_CHAR */ + putStringLong, putStringUlong, putStringInt64, putStringUInt64, + putStringFloat, putStringDouble, putStringEnum, + putStringMenu, putStringDevice}, +/* source is a DBR_CHAR */ {putCharString, putCharChar, putCharUchar, putCharShort, putCharUshort, - putCharLong, putCharUlong, putCharFloat, putCharDouble, putCharEnum, + putCharLong, putCharUlong, putCharInt64, putCharUInt64, + putCharFloat, putCharDouble, putCharEnum, putCharEnum, putCharEnum}, /* source is a DBR_UCHAR */ {putUcharString, putUcharChar, putUcharUchar, putUcharShort, putUcharUshort, - putUcharLong, putUcharUlong, putUcharFloat, putUcharDouble, putUcharEnum, + putUcharLong, putUcharUlong, putUcharInt64, putUcharUInt64, + putUcharFloat, putUcharDouble, putUcharEnum, putUcharEnum, putUcharEnum}, /* source is a DBR_SHORT */ {putShortString, putShortChar, putShortUchar, putShortShort, putShortUshort, - putShortLong, putShortUlong, putShortFloat, putShortDouble, putShortEnum, + putShortLong, putShortUlong, putShortInt64, putShortUInt64, + putShortFloat, putShortDouble, putShortEnum, putShortEnum, putShortEnum}, /* source is a DBR_USHORT */ {putUshortString, putUshortChar, putUshortUchar, putUshortShort, putUshortUshort, - putUshortLong, putUshortUlong, putUshortFloat, putUshortDouble, putUshortEnum, + putUshortLong, putUshortUlong, putUshortInt64, putUshortUInt64, + putUshortFloat, putUshortDouble, putUshortEnum, putUshortEnum, putUshortEnum}, -/* source is a DBR_LONG */ +/* source is a DBR_LONG */ {putLongString, putLongChar, putLongUchar, putLongShort, putLongUshort, - putLongLong, putLongUlong, putLongFloat, putLongDouble, putLongEnum, + putLongLong, putLongUlong, putLongInt64, putLongUInt64, + putLongFloat, putLongDouble, putLongEnum, putLongEnum, putLongEnum}, /* source is a DBR_ULONG */ {putUlongString, putUlongChar, putUlongUchar, putUlongShort, putUlongUshort, - putUlongLong, putUlongUlong, putUlongFloat, putUlongDouble, putUlongEnum, + putUlongLong, putUlongUlong, putUlongInt64, putUlongUInt64, + putUlongFloat, putUlongDouble, putUlongEnum, putUlongEnum, putUlongEnum}, +/* source is a DBR_INT64 */ +{putInt64String, putInt64Char, putInt64Uchar, putInt64Short, putInt64Ushort, + putInt64Long, putInt64Ulong, putInt64Int64, putInt64UInt64, + putInt64Float, putInt64Double, putInt64Enum, + putInt64Enum, putInt64Enum}, +/* source is a DBR_UINT64 */ +{putUInt64String, putUInt64Char, putUInt64Uchar, putUInt64Short, putUInt64Ushort, + putUInt64Long, putUInt64Ulong, putUInt64Int64, putUInt64UInt64, + putUInt64Float, putUInt64Double, putUInt64Enum, + putUInt64Enum, putUInt64Enum}, /* source is a DBR_FLOAT */ {putFloatString, putFloatChar, putFloatUchar, putFloatShort, putFloatUshort, - putFloatLong, putFloatUlong, putFloatFloat, putFloatDouble, putFloatEnum, + putFloatLong, putFloatUlong, putFloatInt64, putFloatUInt64, + putFloatFloat, putFloatDouble, putFloatEnum, putFloatEnum, putFloatEnum}, /* source is a DBR_DOUBLE */ {putDoubleString, putDoubleChar, putDoubleUchar, putDoubleShort, putDoubleUshort, - putDoubleLong, putDoubleUlong, putDoubleFloat, putDoubleDouble, putDoubleEnum, + putDoubleLong, putDoubleUlong, putDoubleInt64, putDoubleUInt64, + putDoubleFloat, putDoubleDouble, putDoubleEnum, putDoubleEnum, putDoubleEnum}, -/* source is a DBR_ENUM */ +/* source is a DBR_ENUM */ {putEnumString, putEnumChar, putEnumUchar, putEnumShort, putEnumUshort, - putEnumLong, putEnumUlong, putEnumFloat, putEnumDouble, putEnumEnum, + putEnumLong, putEnumUlong, putEnumInt64, putEnumUInt64, + putEnumFloat, putEnumDouble, putEnumEnum, putEnumEnum, putEnumEnum} }; diff --git a/src/ioc/db/dbFastLinkConv.c b/src/ioc/db/dbFastLinkConv.c index 8bd053033..27f21fb15 100644 --- a/src/ioc/db/dbFastLinkConv.c +++ b/src/ioc/db/dbFastLinkConv.c @@ -1,17 +1,17 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbFastLinkConv.c */ /* * Author: Matthew Needes * Date: 12-9-93 */ + #include #include #include @@ -55,6 +55,8 @@ * us - epicsUInt16 * l - epicsInt32 * ul - epicsUInt32 + * q - epicsInt64 + * uq - epicsUInt64 * f - epicsFloat32 * d - epicsFloat64 * e - enum @@ -74,16 +76,16 @@ static long cvt_st_st( char *to, const dbAddr *paddr) { - size_t size; + size_t size; - if (paddr && paddr->field_size < MAX_STRING_SIZE) { - size = paddr->field_size - 1; - } else { - size = MAX_STRING_SIZE - 1; - } - strncpy(to, from, size); - to[size] = 0; - return 0; + if (paddr && paddr->field_size < MAX_STRING_SIZE) { + size = paddr->field_size - 1; + } else { + size = MAX_STRING_SIZE - 1; + } + strncpy(to, from, size); + to[size] = 0; + return 0; } /* Convert String to Char */ @@ -92,268 +94,273 @@ static long cvt_st_c( epicsInt8 *to, const dbAddr *paddr) { - char *end; - long value; + char *end; - if (*from == 0) { - *to = 0; - return 0; - } - value = strtol(from, &end, 10); - if (end > from) { - *to = (epicsInt8) value; - return 0; - } - return -1; + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseInt8(from, to, 10, &end); } /* Convert String to Unsigned Char */ static long cvt_st_uc( - char *from, - epicsUInt8 *to, - const dbAddr *paddr) + char *from, + epicsUInt8 *to, + const dbAddr *paddr) { - char *end; - unsigned long value; + char *end; - if (*from == 0) { - *to = 0; - return 0; - } - value = strtoul(from, &end, 10); - if (end > from) { - *to = (epicsUInt8) value; - return 0; - } - return -1; + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseUInt8(from, to, 10, &end); } /* Convert String to Short */ static long cvt_st_s( - char *from, - epicsInt16 *to, - const dbAddr *paddr) + char *from, + epicsInt16 *to, + const dbAddr *paddr) { - char *end; - long value; + char *end; - if (*from == 0) { - *to = 0; - return 0; - } - value = strtol(from, &end, 10); - if (end > from) { - *to = (epicsInt16) value; - return 0; - } - return -1; + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseInt16(from, to, 10, &end); } /* Convert String to Unsigned Short */ static long cvt_st_us( - char *from, - epicsUInt16 *to, - const dbAddr *paddr) + char *from, + epicsUInt16 *to, + const dbAddr *paddr) { - char *end; - unsigned long value; + char *end; - if (*from == 0) { - *to = 0; - return 0; - } - value = strtoul(from, &end, 10); - if (end > from) { - *to = (epicsUInt16) value; - return 0; - } - return -1; + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseUInt16(from, to, 10, &end); } /* Convert String to Long */ static long cvt_st_l( - char *from, - epicsInt32 *to, - const dbAddr *paddr) - { - char *end; - long value; + char *from, + epicsInt32 *to, + const dbAddr *paddr) +{ + char *end; - if (*from == 0) { - *to = 0; - return 0; - } - value = strtol(from, &end, 10); - if (end > from) { - *to = (epicsInt32) value; - return 0; - } - return -1; - } + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseInt32(from, to, 10, &end); +} /* Convert String to Unsigned Long */ static long cvt_st_ul( char *from, epicsUInt32 *to, const dbAddr *paddr) - { - double value; +{ + char *end; + long status; - if (*from == 0) { - *to = 0; - return 0; - } - /*Convert via double so that numbers like 1.0e3 convert properly*/ - /*Problem was old database access said to get unsigned long as double*/ - if (epicsScanDouble(from, &value) == 1) { - *to = (epicsUInt32)value; - return 0; - } - return -1; - } + if (*from == 0) { + *to = 0; + return 0; + } + status = epicsParseUInt32(from, to, 10, &end); + if (status == S_stdlib_noConversion || + (!status && (*end == '.' || *end == 'e' || *end == 'E'))) { + /* + * Convert via double so numbers like 1.0e3 convert properly. + * db_access pretends unsigned long is double. + */ + double dval; + + status = epicsParseFloat64(from, &dval, &end); + if (!status && + dval >=0 && + dval <= ULONG_MAX) + *to = dval; + } + return status; +} + +/* Convert String to Int64 */ +static long cvt_st_q( + char *from, + epicsInt64 *to, + const dbAddr *paddr) +{ + char *end; +printf("cvt_st_q('%s')\n", from); + + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseInt64(from, to, 10, &end); +} + +/* Convert String to UInt64 */ +static long cvt_st_uq( + char *from, + epicsUInt64 *to, + const dbAddr *paddr) +{ + char *end; + + if (*from == 0) { + *to = 0; + return 0; + } + return epicsParseUInt64(from, to, 0, &end); +} /* Convert String to Float */ static long cvt_st_f( char *from, epicsFloat32 *to, const dbAddr *paddr) - { - float value; +{ + char *end; if (*from == 0) { *to = 0; return 0; } - if (epicsScanFloat(from, &value) == 1) { - *to = value; - return 0; - } - return -1; - } + return epicsParseFloat32(from, to, &end); +} /* Convert String to Double */ static long cvt_st_d( char *from, epicsFloat64 *to, const dbAddr *paddr) - { - double value; +{ + char *end; if (*from == 0) { *to = 0.0; return 0; } - if (epicsScanDouble(from, &value) == 1) { - *to = value; - return 0; - } - return -1; - } + return epicsParseFloat64(from, to, &end); +} /* Convert String to Enumerated */ static long cvt_st_e( - char *from, - epicsEnum16 *to, - const dbAddr *paddr) - { - struct rset *prset = 0; - long status; - epicsEnum16 *pfield= (epicsEnum16*)(paddr->pfield); - unsigned int nchoices,ind; - int nargs,nchars; - struct dbr_enumStrs enumStrs; + char *from, + epicsEnum16 *to, + const dbAddr *paddr) +{ + struct rset *prset = dbGetRset(paddr); + long status = S_db_noRSET; + struct dbr_enumStrs enumStrs; - if(paddr && (prset=dbGetRset(paddr)) - && (prset->put_enum_str)) { - status = (*prset->put_enum_str)(paddr,from); - if(!status) return(0); - if(prset->get_enum_strs) { - status = (*prset->get_enum_strs)(paddr,&enumStrs); - if(!status) { - nchoices = enumStrs.no_str; - nargs = sscanf(from,"%u%n",&ind,&nchars); - if(nargs==1 && nchars==strlen(from) && indput_enum_str) { + recGblRecSupError(status, paddr, "dbPutField", "put_enum_str"); + return status; } - if(status == S_db_noRSET) { - recGblRecSupError(status,paddr,"dbPutField","put_enum_str"); - } else { - recGblRecordError(status,(void *)paddr->precord,from); + + status = prset->put_enum_str(paddr, from); + if (!status) return 0; + + if (!prset->get_enum_strs) { + recGblRecSupError(status, paddr, "dbPutField", "get_enum_strs"); + return status; } - return(status); - } + + status = prset->get_enum_strs(paddr, &enumStrs); + if (!status) { + epicsEnum16 val; + + status = epicsParseUInt16(from, &val, 10, NULL); + if (!status && val < enumStrs.no_str) { + *to = val; + return 0; + } + status = S_db_badChoice; + } + + recGblRecordError(status, paddr->precord, from); + return status; +} /* Convert String to Menu */ static long cvt_st_menu( - char *from, - epicsEnum16 *to, - const dbAddr *paddr) + char *from, + epicsEnum16 *to, + const dbAddr *paddr) { - dbFldDes *pdbFldDes = paddr->pfldDes; - dbMenu *pdbMenu = (dbMenu *)pdbFldDes->ftPvt; - char **papChoiceValue; - char *pchoice; - unsigned int nChoice,ind; - int nargs,nchars; + dbFldDes *pdbFldDes = paddr->pfldDes; + dbMenu *pdbMenu; + char **pchoices; + char *pchoice; - if( pdbMenu && (papChoiceValue = pdbMenu->papChoiceValue)) { - nChoice = pdbMenu->nChoice; - for(ind=0; indftPvt) && + (pchoices = pdbMenu->papChoiceValue)) { + int i, nChoice = pdbMenu->nChoice; + epicsEnum16 val; + + for (i = 0; i < nChoice; i++) { + pchoice = pchoices[i]; + if (!pchoice) continue; + if (strcmp(pchoice, from) == 0) { + *to = i; + return 0; + } + } + + if (!epicsParseUInt16(from, &val, 10, NULL) && val < nChoice) { + *to = val; + return 0; + } } - recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_st_menu)"); + recGblDbaddrError(S_db_badChoice, paddr, "dbFastLinkConv(cvt_st_menu)"); return(S_db_badChoice); } /* Convert String to Device */ static long cvt_st_device( - char *from, - epicsEnum16 *to, - const dbAddr *paddr) + char *from, + epicsEnum16 *to, + const dbAddr *paddr) { - dbFldDes *pdbFldDes = paddr->pfldDes; - dbDeviceMenu *pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; - char **papChoice; - char *pchoice; - unsigned int nChoice,ind; - int nargs,nchars; + dbFldDes *pdbFldDes = paddr->pfldDes; + dbDeviceMenu *pdbDeviceMenu = pdbFldDes->ftPvt; + char **pchoices, *pchoice; - if( pdbDeviceMenu && (papChoice = pdbDeviceMenu->papChoice)) { - nChoice = pdbDeviceMenu->nChoice; - for(ind=0; indftPvt) && + (pchoices = pdbDeviceMenu->papChoice)) { + int i, nChoice = pdbDeviceMenu->nChoice; + epicsEnum16 val; + + for (i = 0; i < nChoice; i++) { + pchoice = pchoices[i]; + if (!pchoice) continue; + if (strcmp(pchoice, from) == 0) { + *to = i; + return 0; + } + } + + if (!epicsParseUInt16(from, &val, 10, NULL) && val < nChoice) { + *to = val; + return 0; + } } - recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_st_device)"); - return(S_db_badChoice); + recGblDbaddrError(S_db_badChoice, paddr, "dbFastLinkConv(cvt_st_device)"); + return S_db_badChoice; } /* Convert Char to String */ @@ -405,6 +412,20 @@ static long cvt_c_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Char to Int64 */ +static long cvt_c_q( + epicsInt8 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Char to UInt64 */ +static long cvt_c_uq( + epicsInt8 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Char to Float */ static long cvt_c_f( epicsInt8 *from, @@ -475,6 +496,20 @@ static long cvt_uc_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Unsigned Char to Int64 */ +static long cvt_uc_q( + epicsUInt8 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Unsigned Char to UInt64 */ +static long cvt_uc_uq( + epicsUInt8 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Unsigned Char to Float */ static long cvt_uc_f( epicsUInt8 *from, @@ -545,6 +580,20 @@ static long cvt_s_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Short to Int64 */ +static long cvt_s_q( + epicsInt16 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Short to UInt64 */ +static long cvt_s_uq( + epicsInt16 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Short to Float */ static long cvt_s_f( epicsInt16 *from, @@ -615,6 +664,20 @@ static long cvt_us_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Unsigned Short to Int64 */ +static long cvt_us_q( + epicsUInt16 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Unsigned Short to UInt64 */ +static long cvt_us_uq( + epicsUInt16 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Unsigned Short to Float */ static long cvt_us_f( epicsUInt16 *from, @@ -685,6 +748,20 @@ static long cvt_l_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Long to Int64 */ +static long cvt_l_q( + epicsInt32 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Long to UInt64 */ +static long cvt_l_uq( + epicsInt32 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Long to Float */ static long cvt_l_f( epicsInt32 *from, @@ -755,6 +832,20 @@ static long cvt_ul_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Unsigned Long to Int64 */ +static long cvt_ul_q( + epicsUInt32 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Unsigned Long to UInt64 */ +static long cvt_ul_uq( + epicsUInt32 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Unsigned Long to Float */ static long cvt_ul_f( epicsUInt32 *from, @@ -776,6 +867,180 @@ static long cvt_ul_e( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Int64 to String */ +static long cvt_q_st( + epicsInt64 *from, + char *to, + const dbAddr *paddr) +{ cvtInt64ToString(*from, to); return(0); } + +/* Convert Int64 to Char */ +static long cvt_q_c( + epicsInt64 *from, + epicsInt8 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Unsigned Char */ +static long cvt_q_uc( + epicsInt64 *from, + epicsUInt8 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Short */ +static long cvt_q_s( + epicsInt64 *from, + epicsInt16 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Unsigned Short */ +static long cvt_q_us( + epicsInt64 *from, + epicsUInt16 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Long */ +static long cvt_q_l( + epicsInt64 *from, + epicsInt32 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Unsigned Long */ +static long cvt_q_ul( + epicsInt64 *from, + epicsUInt32 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Int64 */ +static long cvt_q_q( + epicsInt64 *from, + epicsInt64 *to, + const dbAddr *paddr) + { +printf("cvt_q_q(%lld)\n", *from); + + *to=*from; return(0); } + +/* Convert Int64 to UInt64 */ +static long cvt_q_uq( + epicsInt64 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { +printf("cvt_q_qq(%lld)\n", *from); + + *to=*from; return(0); } + +/* Convert Int64 to Float */ +static long cvt_q_f( + epicsInt64 *from, + epicsFloat32 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Double */ +static long cvt_q_d( + epicsInt64 *from, + epicsFloat64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Int64 to Enumerated */ +static long cvt_q_e( + epicsInt32 *from, + epicsEnum16 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to String */ +static long cvt_uq_st( + epicsUInt64 *from, + char *to, + const dbAddr *paddr) +{ cvtUInt64ToString(*from, to); return(0); } + +/* Convert UInt64 to Char */ +static long cvt_uq_c( + epicsUInt64 *from, + epicsInt8 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Unsigned Char */ +static long cvt_uq_uc( + epicsUInt64 *from, + epicsUInt8 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Short */ +static long cvt_uq_s( + epicsUInt64 *from, + epicsInt16 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Unsigned Short */ +static long cvt_uq_us( + epicsUInt64 *from, + epicsUInt16 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Long */ +static long cvt_uq_l( + epicsUInt64 *from, + epicsInt32 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Unsigned Long */ +static long cvt_uq_ul( + epicsUInt64 *from, + epicsUInt32 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Int64 */ +static long cvt_uq_q( + epicsUInt64 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to UInt64 */ +static long cvt_uq_uq( + epicsUInt64 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Float */ +static long cvt_uq_f( + epicsUInt64 *from, + epicsFloat32 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Double */ +static long cvt_uq_d( + epicsUInt64 *from, + epicsFloat64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert UInt64 to Enumerated */ +static long cvt_uq_e( + epicsUInt64 *from, + epicsEnum16 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Float to String */ static long cvt_f_st( epicsFloat32 *from, @@ -836,6 +1101,20 @@ static long cvt_f_ul( const dbAddr *paddr) { *to=(epicsUInt32)*from; return(0); } +/* Convert Float to Int64 */ +static long cvt_f_q( + epicsFloat32 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Float to UInt64 */ +static long cvt_f_uq( + epicsFloat32 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Float to Float */ static long cvt_f_f( epicsFloat32 *from, @@ -908,14 +1187,28 @@ static long cvt_d_l( epicsFloat64 *from, epicsInt32 *to, const dbAddr *paddr) - { *to=(epicsInt32)*from; return(0); } + { *to=*from; return(0); } /* Convert Double to Unsigned Long */ static long cvt_d_ul( epicsFloat64 *from, epicsUInt32 *to, const dbAddr *paddr) - { *to=(epicsUInt32)*from; return(0); } + { *to=*from; return(0); } + +/* Convert Double to Int64 */ +static long cvt_d_q( + epicsFloat64 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Double to UInt64 */ +static long cvt_d_uq( + epicsFloat64 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } /* Convert Double to Float */ static long cvt_d_f( @@ -980,6 +1273,20 @@ static long cvt_e_ul( const dbAddr *paddr) { *to=*from; return(0); } +/* Convert Enumerated to Int64 */ +static long cvt_e_q( + epicsEnum16 *from, + epicsInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + +/* Convert Enumerated to UInt64 */ +static long cvt_e_uq( + epicsEnum16 *from, + epicsUInt64 *to, + const dbAddr *paddr) + { *to=*from; return(0); } + /* Convert Enumerated to Float */ static long cvt_e_f( epicsEnum16 *from, @@ -1085,7 +1392,7 @@ static long cvt_device_st( * Converts type X to ... * * DBR_STRING, DBR_CHR, DBR_UCHAR, DBR_SHORT, DBR_USHORT, - * DBR_LONG, DBR_ULONG, DBR_FLOAT, DBR_DOUBLE, DBR_ENUM + * DBR_LONG, DBR_ULONG, DBR_INT64, DBR_UINT64, DBR_FLOAT, DBR_DOUBLE, DBR_ENUM * * NULL implies the conversion is not supported. */ @@ -1093,40 +1400,46 @@ static long cvt_device_st( epicsShareDef long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])() = { /* Convert DBF_STRING to ... */ -{ cvt_st_st, cvt_st_c, cvt_st_uc, cvt_st_s, cvt_st_us, cvt_st_l, cvt_st_ul, cvt_st_f, cvt_st_d, cvt_st_e }, +{ cvt_st_st, cvt_st_c, cvt_st_uc, cvt_st_s, cvt_st_us, cvt_st_l, cvt_st_ul, cvt_st_q, cvt_st_uq, cvt_st_f, cvt_st_d, cvt_st_e }, /* Convert DBF_CHAR to ... */ -{ cvt_c_st, cvt_c_c, cvt_c_uc, cvt_c_s, cvt_c_us, cvt_c_l, cvt_c_ul, cvt_c_f, cvt_c_d, cvt_c_e }, +{ cvt_c_st, cvt_c_c, cvt_c_uc, cvt_c_s, cvt_c_us, cvt_c_l, cvt_c_ul, cvt_c_q, cvt_c_uq, cvt_c_f, cvt_c_d, cvt_c_e }, /* Convert DBF_UCHAR to ... */ -{ cvt_uc_st, cvt_uc_c, cvt_uc_uc, cvt_uc_s, cvt_uc_us, cvt_uc_l, cvt_uc_ul, cvt_uc_f, cvt_uc_d, cvt_uc_e }, +{ cvt_uc_st, cvt_uc_c, cvt_uc_uc, cvt_uc_s, cvt_uc_us, cvt_uc_l, cvt_uc_ul, cvt_uc_q, cvt_uc_uq, cvt_uc_f, cvt_uc_d, cvt_uc_e }, /* Convert DBF_SHORT to ... */ -{ cvt_s_st, cvt_s_c, cvt_s_uc, cvt_s_s, cvt_s_us, cvt_s_l, cvt_s_ul, cvt_s_f, cvt_s_d, cvt_s_e }, +{ cvt_s_st, cvt_s_c, cvt_s_uc, cvt_s_s, cvt_s_us, cvt_s_l, cvt_s_ul, cvt_s_q, cvt_s_uq, cvt_s_f, cvt_s_d, cvt_s_e }, /* Convert DBF_USHORT to ... */ -{ cvt_us_st, cvt_us_c, cvt_us_uc, cvt_us_s, cvt_us_us, cvt_us_l, cvt_us_ul, cvt_us_f, cvt_us_d, cvt_us_e }, +{ cvt_us_st, cvt_us_c, cvt_us_uc, cvt_us_s, cvt_us_us, cvt_us_l, cvt_us_ul, cvt_us_q, cvt_us_uq, cvt_us_f, cvt_us_d, cvt_us_e }, /* Convert DBF_LONG to ... */ -{ cvt_l_st, cvt_l_c, cvt_l_uc, cvt_l_s, cvt_l_us, cvt_l_l, cvt_l_ul, cvt_l_f, cvt_l_d, cvt_l_e }, +{ cvt_l_st, cvt_l_c, cvt_l_uc, cvt_l_s, cvt_l_us, cvt_l_l, cvt_l_ul, cvt_l_q, cvt_l_uq, cvt_l_f, cvt_l_d, cvt_l_e }, /* Convert DBF_ULONG to ... */ -{ cvt_ul_st, cvt_ul_c, cvt_ul_uc, cvt_ul_s, cvt_ul_us, cvt_ul_l, cvt_ul_ul, cvt_ul_f, cvt_ul_d, cvt_ul_e }, +{ cvt_ul_st, cvt_ul_c, cvt_ul_uc, cvt_ul_s, cvt_ul_us, cvt_ul_l, cvt_ul_ul, cvt_ul_q, cvt_ul_uq, cvt_ul_f, cvt_ul_d, cvt_ul_e }, + + /* Convert DBF_INT64 to ... */ +{ cvt_q_st, cvt_q_c, cvt_q_uc, cvt_q_s, cvt_q_us, cvt_q_l, cvt_q_ul, cvt_q_q, cvt_q_uq, cvt_q_f, cvt_q_d, cvt_q_e }, + + /* Convert DBF_UINT64 to ... */ +{ cvt_uq_st, cvt_uq_c, cvt_uq_uc, cvt_uq_s, cvt_uq_us, cvt_uq_l, cvt_uq_ul, cvt_uq_q, cvt_uq_uq, cvt_uq_f, cvt_uq_d, cvt_uq_e }, /* Convert DBF_FLOAT to ... */ -{ cvt_f_st, cvt_f_c, cvt_f_uc, cvt_f_s, cvt_f_us, cvt_f_l, cvt_f_ul, cvt_f_f, cvt_f_d, cvt_f_e }, +{ cvt_f_st, cvt_f_c, cvt_f_uc, cvt_f_s, cvt_f_us, cvt_f_l, cvt_f_ul, cvt_f_q, cvt_f_uq, cvt_f_f, cvt_f_d, cvt_f_e }, /* Convert DBF_DOUBLE to ... */ -{ cvt_d_st, cvt_d_c, cvt_d_uc, cvt_d_s, cvt_d_us, cvt_d_l, cvt_d_ul, cvt_d_f, cvt_d_d, cvt_d_e }, +{ cvt_d_st, cvt_d_c, cvt_d_uc, cvt_d_s, cvt_d_us, cvt_d_l, cvt_d_ul, cvt_d_q, cvt_d_uq, cvt_d_f, cvt_d_d, cvt_d_e }, /* Convert DBF_ENUM to ... */ -{ cvt_e_st_get, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_f, cvt_e_d, cvt_e_e }, +{ cvt_e_st_get, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_q, cvt_e_uq, cvt_e_f, cvt_e_d, cvt_e_e }, /* Convert DBF_MENU to ... */ -{ cvt_menu_st, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_f, cvt_e_d, cvt_e_e }, +{ cvt_menu_st, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_q, cvt_e_uq, cvt_e_f, cvt_e_d, cvt_e_e }, /* Convert DBF_DEVICE to ... */ -{ cvt_device_st, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_f, cvt_e_d, cvt_e_e } }; +{ cvt_device_st, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_q, cvt_e_uq, cvt_e_f, cvt_e_d, cvt_e_e } }; /* * Put conversion routine lookup table @@ -1134,8 +1447,8 @@ epicsShareDef long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])() = { * Converts type X to ... * * DBF_STRING DBF_CHAR DBF_UCHAR DBF_SHORT DBF_USHORT - * DBF_LONG DBF_ULONG DBF_FLOAT DBF_DOUBLE DBF_ENUM - * DBF_MENU DBF_DEVICE + * DBF_LONG DBF_ULONG DBF_INT64 DBF_UINT64 DBF_FLOAT DBF_DOUBLE DBF_ENUM + * DBF_MENU DBF_DEVICE * * NULL implies the conversion is not supported. */ @@ -1143,32 +1456,38 @@ epicsShareDef long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])() = { epicsShareDef long (*dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1])() = { /* Convert DBR_STRING to ... */ -{ cvt_st_st, cvt_st_c, cvt_st_uc, cvt_st_s, cvt_st_us, cvt_st_l, cvt_st_ul, cvt_st_f, cvt_st_d, cvt_st_e, cvt_st_menu, cvt_st_device}, +{ cvt_st_st, cvt_st_c, cvt_st_uc, cvt_st_s, cvt_st_us, cvt_st_l, cvt_st_ul, cvt_st_q, cvt_st_uq, cvt_st_f, cvt_st_d, cvt_st_e, cvt_st_menu, cvt_st_device}, /* Convert DBR_CHAR to ... */ -{ cvt_c_st, cvt_c_c, cvt_c_uc, cvt_c_s, cvt_c_us, cvt_c_l, cvt_c_ul, cvt_c_f, cvt_c_d, cvt_c_e, cvt_c_e, cvt_c_e}, +{ cvt_c_st, cvt_c_c, cvt_c_uc, cvt_c_s, cvt_c_us, cvt_c_l, cvt_c_ul, cvt_c_q, cvt_c_uq, cvt_c_f, cvt_c_d, cvt_c_e, cvt_c_e, cvt_c_e}, /* Convert DBR_UCHAR to ... */ -{ cvt_uc_st, cvt_uc_c, cvt_uc_uc, cvt_uc_s, cvt_uc_us, cvt_uc_l, cvt_uc_ul, cvt_uc_f, cvt_uc_d, cvt_uc_e, cvt_uc_e, cvt_uc_e}, +{ cvt_uc_st, cvt_uc_c, cvt_uc_uc, cvt_uc_s, cvt_uc_us, cvt_uc_l, cvt_uc_ul, cvt_uc_q, cvt_uc_uq, cvt_uc_f, cvt_uc_d, cvt_uc_e, cvt_uc_e, cvt_uc_e}, /* Convert DBR_SHORT to ... */ -{ cvt_s_st, cvt_s_c, cvt_s_uc, cvt_s_s, cvt_s_us, cvt_s_l, cvt_s_ul, cvt_s_f, cvt_s_d, cvt_s_e, cvt_s_e, cvt_s_e}, +{ cvt_s_st, cvt_s_c, cvt_s_uc, cvt_s_s, cvt_s_us, cvt_s_l, cvt_s_ul, cvt_s_q, cvt_s_uq, cvt_s_f, cvt_s_d, cvt_s_e, cvt_s_e, cvt_s_e}, /* Convert DBR_USHORT to ... */ -{ cvt_us_st, cvt_us_c, cvt_us_uc, cvt_us_s, cvt_us_us, cvt_us_l, cvt_us_ul, cvt_us_f, cvt_us_d, cvt_us_e, cvt_us_e, cvt_us_e}, +{ cvt_us_st, cvt_us_c, cvt_us_uc, cvt_us_s, cvt_us_us, cvt_us_l, cvt_us_ul, cvt_us_q, cvt_us_uq, cvt_us_f, cvt_us_d, cvt_us_e, cvt_us_e, cvt_us_e}, /* Convert DBR_LONG to ... */ -{ cvt_l_st, cvt_l_c, cvt_l_uc, cvt_l_s, cvt_l_us, cvt_l_l, cvt_l_ul, cvt_l_f, cvt_l_d, cvt_l_e, cvt_l_e, cvt_l_e}, +{ cvt_l_st, cvt_l_c, cvt_l_uc, cvt_l_s, cvt_l_us, cvt_l_l, cvt_l_ul, cvt_l_q, cvt_l_uq, cvt_l_f, cvt_l_d, cvt_l_e, cvt_l_e, cvt_l_e}, /* Convert DBR_ULONG to ... */ -{ cvt_ul_st, cvt_ul_c, cvt_ul_uc, cvt_ul_s, cvt_ul_us, cvt_ul_l, cvt_ul_ul, cvt_ul_f, cvt_ul_d, cvt_ul_e, cvt_ul_e, cvt_ul_e}, +{ cvt_ul_st, cvt_ul_c, cvt_ul_uc, cvt_ul_s, cvt_ul_us, cvt_ul_l, cvt_ul_ul, cvt_ul_q, cvt_ul_uq, cvt_ul_f, cvt_ul_d, cvt_ul_e, cvt_ul_e, cvt_ul_e}, + + /* Convert DBR_INT64 to ... */ +{ cvt_q_st, cvt_q_c, cvt_q_uc, cvt_q_s, cvt_q_us, cvt_q_l, cvt_q_ul, cvt_q_q, cvt_q_uq, cvt_q_f, cvt_q_d, cvt_q_e, cvt_q_e, cvt_q_e}, + + /* Convert DBR_UINT64 to ... */ +{ cvt_uq_st, cvt_uq_c, cvt_uq_uc, cvt_uq_s, cvt_uq_us, cvt_uq_l, cvt_uq_ul, cvt_uq_q, cvt_uq_uq, cvt_uq_f, cvt_uq_d, cvt_uq_e, cvt_uq_e, cvt_uq_e}, /* Convert DBR_FLOAT to ... */ -{ cvt_f_st, cvt_f_c, cvt_f_uc, cvt_f_s, cvt_f_us, cvt_f_l, cvt_f_ul, cvt_f_f, cvt_f_d, cvt_f_e, cvt_f_e, cvt_f_e}, +{ cvt_f_st, cvt_f_c, cvt_f_uc, cvt_f_s, cvt_f_us, cvt_f_l, cvt_f_ul, cvt_f_q, cvt_f_uq, cvt_f_f, cvt_f_d, cvt_f_e, cvt_f_e, cvt_f_e}, /* Convert DBR_DOUBLE to ... */ -{ cvt_d_st, cvt_d_c, cvt_d_uc, cvt_d_s, cvt_d_us, cvt_d_l, cvt_d_ul, cvt_d_f, cvt_d_d, cvt_d_e, cvt_d_e, cvt_d_e}, +{ cvt_d_st, cvt_d_c, cvt_d_uc, cvt_d_s, cvt_d_us, cvt_d_l, cvt_d_ul, cvt_d_q, cvt_d_uq, cvt_d_f, cvt_d_d, cvt_d_e, cvt_d_e, cvt_d_e}, /* Convert DBR_ENUM to ... */ -{ cvt_e_st_put, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_f, cvt_e_d, cvt_e_e, cvt_e_e, cvt_e_e} }; +{ cvt_e_st_put, cvt_e_c, cvt_e_uc, cvt_e_s, cvt_e_us, cvt_e_l, cvt_e_ul, cvt_e_q, cvt_e_uq, cvt_e_f, cvt_e_d, cvt_e_e, cvt_e_e, cvt_e_e} }; diff --git a/src/ioc/db/dbTest.c b/src/ioc/db/dbTest.c index 97279de08..d5d5d0cc6 100644 --- a/src/ioc/db/dbTest.c +++ b/src/ioc/db/dbTest.c @@ -13,6 +13,7 @@ #include #include +#include "cvtFast.h" #include "dbDefs.h" #include "ellLib.h" #include "epicsMutex.h" @@ -72,13 +73,13 @@ static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size); static char *dbf[DBF_NTYPES] = { "STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG", - "FLOAT","DOUBLE","ENUM","MENU","DEVICE", + "INT64","UINT64","FLOAT","DOUBLE","ENUM","MENU","DEVICE", "INLINK","OUTLINK","FWDLINK","NOACCESS" }; static char *dbr[DBR_ENUM+2] = { "STRING","CHAR","UCHAR","SHORT","USHORT","LONG","ULONG", - "FLOAT","DOUBLE","ENUM","NOACCESS" + "INT64","UINT64","FLOAT","DOUBLE","ENUM","NOACCESS" }; long dba(const char*pname) @@ -484,6 +485,16 @@ long dbtgf(const char *pname) status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); + dbr_type = DBR_INT64; + no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64))); + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); + printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); + + dbr_type = DBR_UINT64; + no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64))); + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); + printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); + dbr_type = DBR_FLOAT; no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32))); status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); @@ -510,17 +521,7 @@ long dbtpf(const char *pname, const char *pvalue) long buffer[100]; long *pbuffer = buffer; DBADDR addr; - long status = 0; - long options, no_elements; - char *pend; - long val_long; - int validLong; - unsigned long val_ulong; - int validULong; - int valid = 1; int put_type; - epicsFloat32 fvalue; - epicsFloat64 dvalue; static TAB_BUFFER msg_Buff; TAB_BUFFER *pMsgBuff = &msg_Buff; char *pmsg = pMsgBuff->message; @@ -530,91 +531,90 @@ long dbtpf(const char *pname, const char *pvalue) printf("Usage: dbtpf \"pv name\", \"value\"\n"); return 1; } - if (nameToAddr(pname, &addr)) return -1; - val_long = strtol(pvalue, &pend, 10); - validLong = (*pend == 0); - - val_ulong = strtoul(pvalue, &pend, 10); - validULong = (*pend == 0); - for (put_type = DBR_STRING; put_type <= DBF_ENUM; put_type++) { + union { + epicsInt8 i8; + epicsUInt8 u8; + epicsInt16 i16; + epicsUInt16 u16; + epicsInt32 i32; + epicsUInt32 u32; + epicsInt64 i64; + epicsUInt64 u64; + epicsFloat32 f32; + epicsFloat64 f64; + epicsEnum16 e16; + } val; + const void *pval = &val; + int valid = 1; + switch (put_type) { case DBR_STRING: - status = dbPutField(&addr, put_type, pvalue, 1L); + pval = pvalue; break; case DBR_CHAR: - if ((valid = validLong)) { - epicsInt8 val_i8 = (epicsInt8)val_long; - status = dbPutField(&addr, put_type, &val_i8, 1L); - } + valid = !epicsParseInt8(pvalue, &val.i8, 10, NULL); break; case DBR_UCHAR: - if ((valid = validULong)) { - epicsUInt8 val_u8 = (epicsUInt8)val_ulong; - status = dbPutField(&addr, put_type, &val_u8, 1L); - } + valid = !epicsParseUInt8(pvalue, &val.u8, 10, NULL); break; case DBR_SHORT: - if ((valid = validLong)) { - epicsInt16 val_i16 = (epicsInt16) val_long; - status = dbPutField(&addr, put_type, &val_i16,1L); - } + valid = !epicsParseInt16(pvalue, &val.i16, 10, NULL); break; case DBR_USHORT: - if ((valid = validULong)) { - epicsUInt16 val_u16 = (epicsUInt16) val_ulong; - status = dbPutField(&addr, put_type, &val_u16, 1L); - } + valid = !epicsParseUInt16(pvalue, &val.u16, 10, NULL); break; case DBR_LONG: - if ((valid = validLong)) { - epicsInt32 val_i32 = val_long; - status = dbPutField(&addr, put_type,&val_i32,1L); - } + valid = !epicsParseInt32(pvalue, &val.i32, 10, NULL); break; case DBR_ULONG: - if ((valid = validULong)) { - epicsUInt32 val_u32 = val_ulong; - status = dbPutField(&addr, put_type, &val_u32, 1L); - } + valid = !epicsParseUInt32(pvalue, &val.u32, 10, NULL); + break; + case DBR_INT64: + valid = !epicsParseInt64(pvalue, &val.i64, 10, NULL); + break; + case DBR_UINT64: + valid = !epicsParseUInt64(pvalue, &val.u64, 10, NULL); break; case DBR_FLOAT: - if ((valid = epicsScanFloat(pvalue, &fvalue) == 1)) - status = dbPutField(&addr, put_type, &fvalue, 1L); + valid = !epicsParseFloat32(pvalue, &val.f32, NULL); break; case DBR_DOUBLE: - if ((valid = epicsScanDouble(pvalue, &dvalue) == 1)) - status = dbPutField(&addr, put_type, &dvalue, 1L); + valid = !epicsParseFloat64(pvalue, &val.f64, NULL); break; case DBR_ENUM: - if ((valid = validULong)) { - epicsEnum16 val_e16 = (epicsEnum16) val_ulong; - status = dbPutField(&addr, put_type, &val_e16, 1L); - } + valid = !epicsParseUInt16(pvalue, &val.e16, 10, NULL); break; } if (valid) { + long status = dbPutField(&addr, put_type, pval, 1); + if (status) { - printf("Put as DBR_%s Failed.\n", dbr[put_type]); - } else { - printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]); - no_elements = MIN(addr.no_elements, + printf("Put as DBR_%-6s Failed.\n", dbr[put_type]); + } + else { + long options = 0; + long no_elements = MIN(addr.no_elements, ((sizeof(buffer))/addr.field_size)); - options = 0; + + printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]); status = dbGetField(&addr, addr.dbr_field_type, pbuffer, &options, &no_elements, NULL); printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L, no_elements, pMsgBuff, tab_size); } } + else { + printf("Cvt to DBR_%s failed.\n", dbr[put_type]); + } } pmsg[0] = '\0'; dbpr_msgOut(pMsgBuff, tab_size); - return(0); + return 0; } long dbior(const char *pdrvName,int interest_level) @@ -732,10 +732,8 @@ static void printBuffer( long status, short dbr_type, void *pbuffer, long reqOptions, long retOptions, long no_elements, TAB_BUFFER *pMsgBuff, int tab_size) { - epicsInt32 val_i32; - epicsUInt32 val_u32; char *pmsg = pMsgBuff->message; - size_t i, len; + int i; if (reqOptions & DBR_STATUS) { if (retOptions & DBR_STATUS) { @@ -898,221 +896,166 @@ static void printBuffer( if (no_elements == 0) return; - switch (dbr_type) { - case (DBR_STRING): - if (no_elements == 1) - sprintf(pmsg, "DBR_STRING: "); - else - sprintf(pmsg, "DBR_STRING[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, "DBR_STRING: failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } + if (no_elements == 1) + sprintf(pmsg, "DBF_%s: ", dbr[dbr_type]); + else + sprintf(pmsg, "DBF_%s[%ld]: ", dbr[dbr_type], no_elements); + dbpr_msgOut(pMsgBuff, tab_size); - for(i=0; i 0) { - sprintf(pmsg, " \"%s\"", (char *)pbuffer); + if (status != 0) { + strcpy(pmsg, "failed."); + dbpr_msgOut(pMsgBuff, tab_size); + } + else { + switch (dbr_type) { + case DBR_STRING: + for(i=0; i MAXLINE - 5) width = MAXLINE - 5; - sprintf(pmsg, " \"%.*s\"", width, (char *)pbuffer + i); - if (i + MAXLINE - 5 < no_elements) strcat(pmsg, " +"); + case DBR_CHAR: + if (no_elements == 1) { + epicsInt32 val = *(epicsInt8 *) pbuffer; + + if (isprint(val)) + sprintf(pmsg, "%d = 0x%x = '%c'", val, val & 0xff, val); + else + sprintf(pmsg, "%d = 0x%x", val, val & 0xff); dbpr_msgOut(pMsgBuff, tab_size); + } else { + size_t len = epicsStrnLen(pbuffer, no_elements); + + i = 0; + while (len > 0) { + int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len; + + sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i); + len -= chunk; + if (len > 0) + strcat(pmsg, " +"); + dbpr_msgOut(pMsgBuff, tab_size); + } } - } - break; + break; - case (DBR_UCHAR): - if (no_elements == 1) - sprintf(pmsg, "DBR_UCHAR: "); - else - sprintf(pmsg, "DBR_UCHAR[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); + case DBR_UCHAR: + for (i = 0; i < no_elements; i++) { + epicsUInt32 val = *(epicsUInt8 *) pbuffer; + + sprintf(pmsg, "%u = 0x%x", val, val); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsUInt8); + } + break; + + case DBR_SHORT: + for (i = 0; i < no_elements; i++) { + epicsInt32 val = *(epicsInt16 *) pbuffer; + + sprintf(pmsg, "%hd = 0x%hx", val, val); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsInt16); + } + break; + + case DBR_USHORT: + for (i = 0; i < no_elements; i++) { + epicsUInt32 val = *(epicsUInt16 *) pbuffer; + + sprintf(pmsg, "%hu = 0x%hx", val, val); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsUInt16); + } + break; + + case DBR_LONG: + for (i = 0; i < no_elements; i++) { + epicsInt32 val = *(epicsInt32 *) pbuffer; + + sprintf(pmsg, "%d = 0x%x", val, val); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsInt32); + } + break; + + case DBR_ULONG: + for (i = 0; i < no_elements; i++) { + epicsUInt32 val = *(epicsUInt32 *) pbuffer; + + sprintf(pmsg, "%u = 0x%x", val, val); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsUInt32); + } + break; + + case DBR_INT64: + for (i = 0; i < no_elements; i++) { + epicsInt64 val = *(epicsInt64 *) pbuffer; + + pmsg += cvtInt64ToString(val, pmsg); + strcpy(pmsg, " = "); + pmsg += 3; + cvtInt64ToHexString(val, pmsg); + dbpr_msgOut(pMsgBuff, tab_size); + pmsg = pMsgBuff->message; + pbuffer = (char *)pbuffer + sizeof(epicsInt64); + } + break; + + case DBR_UINT64: + for (i = 0; i < no_elements; i++) { + epicsUInt64 val = *(epicsUInt64 *) pbuffer; + + pmsg += cvtUInt64ToString(val, pmsg); + strcpy(pmsg, " = "); + pmsg += 3; + cvtUInt64ToHexString(val, pmsg); + dbpr_msgOut(pMsgBuff, tab_size); + pmsg = pMsgBuff->message; + pbuffer = (char *)pbuffer + sizeof(epicsUInt64); + } + break; + + case DBR_FLOAT: + for (i = 0; i < no_elements; i++) { + sprintf(pmsg, "%.6g", *((epicsFloat32 *) pbuffer)); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsFloat32); + } + break; + + case DBR_DOUBLE: + for (i = 0; i < no_elements; i++) { + sprintf(pmsg, "%.12g", *((epicsFloat64 *) pbuffer)); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsFloat64); + } + break; + + case DBR_ENUM: + for (i = 0; i < no_elements; i++) { + sprintf(pmsg, "%u", *((epicsEnum16 *) pbuffer)); + dbpr_msgOut(pMsgBuff, tab_size); + pbuffer = (char *)pbuffer + sizeof(epicsEnum16); + } + break; + + default: + sprintf(pmsg, "Bad DBR type %d", dbr_type); dbpr_msgOut(pMsgBuff, tab_size); break; } - - for (i = 0; i < no_elements; i++) { - val_u32 = *(epicsUInt8 *) pbuffer; - sprintf(pmsg, "%-9u 0x%-9x", val_u32, val_u32); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsUInt8); - } - break; - - case (DBR_SHORT): - if (no_elements == 1) - sprintf(pmsg, "DBR_SHORT: "); - else - sprintf(pmsg, "DBR_SHORT[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - val_i32 = *(epicsInt16 *) pbuffer; - sprintf(pmsg, "%-9d 0x%-9x", val_i32, val_i32); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsInt16); - } - break; - - case (DBR_USHORT): - if (no_elements == 1) - sprintf(pmsg, "DBR_USHORT: "); - else - sprintf(pmsg, "DBR_USHORT[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - val_u32 = *(epicsUInt16 *) pbuffer; - sprintf(pmsg, "%-9u 0x%-9x", val_u32, val_u32); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsUInt16); - } - break; - - case (DBR_LONG): - if (no_elements == 1) - sprintf(pmsg, "DBR_LONG: "); - else - sprintf(pmsg, "DBR_LONG[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - val_i32 = *(epicsInt32 *) pbuffer; - sprintf(pmsg, "%-9d 0x%-9x", val_i32, val_i32); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsInt32); - } - break; - - case (DBR_ULONG): - if (no_elements == 1) - sprintf(pmsg, "DBR_ULONG: "); - else - sprintf(pmsg, "DBR_ULONG[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - val_u32 = *(epicsUInt32 *) pbuffer; - sprintf(pmsg, "%-9u 0x%-9x", val_u32, val_u32); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsUInt32); - } - break; - - case (DBR_FLOAT): - if (no_elements == 1) - sprintf(pmsg, "DBR_FLOAT: "); - else - sprintf(pmsg, "DBR_FLOAT[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - sprintf(pmsg, "%-13.6g", *((epicsFloat32 *) pbuffer)); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsFloat32); - } - break; - - case (DBR_DOUBLE): - if (no_elements == 1) - sprintf(pmsg, "DBR_DOUBLE: "); - else - sprintf(pmsg, "DBR_DOUBLE[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - sprintf(pmsg, "%-13.6g", *((epicsFloat64 *) pbuffer)); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsFloat64); - } - break; - - case (DBR_ENUM): - if (no_elements == 1) - sprintf(pmsg, "DBR_ENUM: "); - else - sprintf(pmsg, "DBR_ENUM[%ld]: ", no_elements); - dbpr_msgOut(pMsgBuff, tab_size); - if (status != 0) { - sprintf(pmsg, " failed."); - dbpr_msgOut(pMsgBuff, tab_size); - break; - } - - for (i = 0; i < no_elements; i++) { - sprintf(pmsg, "%-9u", *((epicsEnum16 *) pbuffer)); - dbpr_msgOut(pMsgBuff, tab_size); - pbuffer = (char *)pbuffer + sizeof(epicsEnum16); - } - break; - - default: - printf(" illegal request type."); - break; } dbpr_msg_flush(pMsgBuff, tab_size); - return; } static int dbpr_report( @@ -1144,7 +1087,6 @@ static int dbpr_report( pfield = ((char *)paddr->precord) + pdbFldDes->offset; if (pdbFldDes->interest > interest_level ) continue; - switch (pdbFldDes->field_type) { case DBF_STRING: case DBF_USHORT: @@ -1155,6 +1097,8 @@ static int dbpr_report( case DBF_SHORT: case DBF_LONG: case DBF_ULONG: + case DBF_INT64: + case DBF_UINT64: case DBF_DOUBLE: case DBF_MENU: case DBF_DEVICE: diff --git a/src/ioc/db/db_convert.h b/src/ioc/db/db_convert.h index 694c0dd07..d06164f02 100644 --- a/src/ioc/db/db_convert.h +++ b/src/ioc/db/db_convert.h @@ -23,8 +23,8 @@ epicsShareExtern struct dbBase *pdbbase; epicsShareExtern volatile int interruptAccept; /*Definitions that allow old database access to use new conversion routines*/ -#define newDBF_DEVICE 11 -#define newDBR_ENUM 9 +#define newDBF_DEVICE 13 +#define newDBR_ENUM 11 epicsShareExtern long (*dbGetConvertRoutine[newDBF_DEVICE+1][newDBR_ENUM+1]) (struct dbAddr *paddr, void *pbuffer,long nRequest, long no_elements, long offset); @@ -43,11 +43,11 @@ epicsShareExtern unsigned short dbDBRnewToDBRold[newDBR_ENUM+1]; epicsShareDef unsigned short dbDBRoldToDBFnew[DBR_DOUBLE+1] = { 0, /*DBR_STRING to DBF_STRING*/ 3, /*DBR_INT to DBF_SHORT*/ - 7, /*DBR_FLOAT to DBF_FLOAT*/ - 9, /*DBR_ENUM to DBF_ENUM*/ + 9, /*DBR_FLOAT to DBF_FLOAT*/ + 11, /*DBR_ENUM to DBF_ENUM*/ 1, /*DBR_CHAR to DBF_CHAR*/ 5, /*DBR_LONG to DBF_LONG*/ - 8 /*DBR_DOUBLE to DBF_DOUBLE*/ + 10 /*DBR_DOUBLE to DBF_DOUBLE*/ }; epicsShareDef unsigned short dbDBRnewToDBRold[newDBR_ENUM+1] = { 0, /*DBR_STRING to DBR_STRING*/ @@ -57,6 +57,8 @@ epicsShareDef unsigned short dbDBRnewToDBRold[newDBR_ENUM+1] = { 5, /*DBR_USHORT to DBR_LONG*/ 5, /*DBR_LONG to DBR_LONG*/ 6, /*DBR_ULONG to DBR_DOUBLE*/ + 6, /*DBR_INT64 to DBR_DOUBLE*/ + 6, /*DBR_UINT64 to DBR_DOUBLE*/ 2, /*DBR_FLOAT to DBR_FLOAT*/ 6, /*DBR_DOUBLE to DBR_DOUBLE*/ 3, /*DBR_ENUM to DBR_ENUM*/ diff --git a/src/ioc/db/menuFtype.dbd b/src/ioc/db/menuFtype.dbd index ff20e0ca4..af6a8803d 100644 --- a/src/ioc/db/menuFtype.dbd +++ b/src/ioc/db/menuFtype.dbd @@ -1,10 +1,9 @@ #************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found +# EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* menu(menuFtype) { @@ -15,6 +14,8 @@ menu(menuFtype) { choice(menuFtypeUSHORT,"USHORT") choice(menuFtypeLONG,"LONG") choice(menuFtypeULONG,"ULONG") + choice(menuFtypeINT64,"INT64") + choice(menuFtypeUINT64,"UINT64") choice(menuFtypeFLOAT,"FLOAT") choice(menuFtypeDOUBLE,"DOUBLE") choice(menuFtypeENUM,"ENUM") diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index f1e3e7e62..36e0eaf60 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -120,6 +120,8 @@ void recGblGetPrec(const struct dbAddr *paddr, long *precision) case DBF_USHORT: case DBF_LONG: case DBF_ULONG: + case DBF_INT64: + case DBF_UINT64: *precision = 0; break; @@ -325,7 +327,15 @@ static void getMaxRangeValues(short field_type, double *pupper_limit, *plower_limit = -2147483648.0; break; case DBF_ULONG: - *pupper_limit = (double) 0xffffffffU; + *pupper_limit = 4294967295.0; + *plower_limit = 0.0; + break; + case DBF_INT64: + *pupper_limit = 9223372036854775808.0; + *plower_limit = -9223372036854775808.0; + break; + case DBF_UINT64: + *pupper_limit = 18446744073709551615.0; *plower_limit = 0.0; break; case DBF_FLOAT: diff --git a/src/ioc/dbStatic/dbFldTypes.h b/src/ioc/dbStatic/dbFldTypes.h index 0d2b9e1da..ba1a69573 100644 --- a/src/ioc/dbStatic/dbFldTypes.h +++ b/src/ioc/dbStatic/dbFldTypes.h @@ -29,6 +29,8 @@ typedef enum { DBF_USHORT, DBF_LONG, DBF_ULONG, + DBF_INT64, + DBF_UINT64, DBF_FLOAT, DBF_DOUBLE, DBF_ENUM, @@ -56,6 +58,8 @@ epicsShareDef mapdbfType pamapdbfType[DBF_NTYPES] = { {"DBF_USHORT",DBF_USHORT}, {"DBF_LONG",DBF_LONG}, {"DBF_ULONG",DBF_ULONG}, + {"DBF_INT64",DBF_INT64}, + {"DBF_UINT64",DBF_UINT64}, {"DBF_FLOAT",DBF_FLOAT}, {"DBF_DOUBLE",DBF_DOUBLE}, {"DBF_ENUM",DBF_ENUM}, @@ -76,6 +80,8 @@ epicsShareDef mapdbfType pamapdbfType[DBF_NTYPES] = { #define DBR_USHORT DBF_USHORT #define DBR_LONG DBF_LONG #define DBR_ULONG DBF_ULONG +#define DBR_INT64 DBF_INT64 +#define DBR_UINT64 DBF_UINT64 #define DBR_FLOAT DBF_FLOAT #define DBR_DOUBLE DBF_DOUBLE #define DBR_ENUM DBF_ENUM diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 91c82b702..3da71cf4e 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -227,7 +227,7 @@ void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) va_end(args); } -static void ulongToHexString(epicsUInt32 source,char *pdest) +static void ulongToHexString(epicsUInt32 source, char *pdest) { static const char hex_digit_to_ascii[16] = "0123456789abcdef"; epicsUInt32 val,temp; @@ -1854,6 +1854,8 @@ char * dbGetString(DBENTRY *pdbentry) case DBF_ENUM: case DBF_LONG: case DBF_ULONG: + case DBF_INT64: + case DBF_UINT64: case DBF_FLOAT: case DBF_DOUBLE: case DBF_MENU: @@ -2011,60 +2013,72 @@ char *dbGetStringNum(DBENTRY *pdbentry) cvttype = pflddes->base; switch (pflddes->field_type) { case DBF_CHAR: - if (cvttype==CT_DECIMAL) - cvtCharToString(*(char*)pfield, message); + if (cvttype == CT_DECIMAL) + cvtCharToString(*(char *) pfield, message); else - ulongToHexString((epicsUInt32)(*(char*)pfield),message); + ulongToHexString(*(char *) pfield, message); break; case DBF_UCHAR: if (cvttype==CT_DECIMAL) - cvtUcharToString(*(unsigned char*)pfield, message); + cvtUcharToString(*(epicsUInt8 *) pfield, message); else - ulongToHexString((epicsUInt32)(*(unsigned char*)pfield),message); + ulongToHexString(*(epicsUInt8 *) pfield, message); break; case DBF_SHORT: if (cvttype==CT_DECIMAL) - cvtShortToString(*(short*)pfield, message); + cvtShortToString(*(epicsInt16 *) pfield, message); else - ulongToHexString((epicsUInt32)(*(short*)pfield),message); + ulongToHexString(*(epicsInt16 *) pfield, message); break; case DBF_USHORT: case DBF_ENUM: if (cvttype==CT_DECIMAL) - cvtUshortToString(*(unsigned short*)pfield, message); + cvtUshortToString(*(epicsUInt16 *) pfield, message); else - ulongToHexString((epicsUInt32)(*(unsigned short*)pfield),message); + ulongToHexString(*(epicsUInt16 *) pfield, message); break; case DBF_LONG: if (cvttype==CT_DECIMAL) - cvtLongToString(*(epicsInt32*)pfield, message); + cvtLongToString(*(epicsInt32 *) pfield, message); else - ulongToHexString((epicsUInt32)(*(epicsInt32*)pfield), message); + ulongToHexString(*(epicsInt32 *) pfield, message); break; case DBF_ULONG: if (cvttype==CT_DECIMAL) - cvtUlongToString(*(epicsUInt32 *)pfield, message); + cvtUlongToString(*(epicsUInt32 *) pfield, message); else - ulongToHexString(*(epicsUInt32*)pfield, message); + ulongToHexString(*(epicsUInt32 *) pfield, message); + break; + case DBF_INT64: + if (cvttype==CT_DECIMAL) + cvtInt64ToString(*(epicsInt64 *) pfield, message); + else + cvtInt64ToHexString(*(epicsInt64 *) pfield, message); + break; + case DBF_UINT64: + if (cvttype==CT_DECIMAL) + cvtUInt64ToString(*(epicsUInt32 *) pfield, message); + else + cvtUInt64ToHexString(*(epicsUInt32 *) pfield, message); break; case DBF_FLOAT: - floatToString(*(float *)pfield,message); + floatToString(*(epicsFloat32 *) pfield, message); break; case DBF_DOUBLE: - doubleToString(*(double *)pfield,message); + doubleToString(*(epicsFloat64 *) pfield, message); break; case DBF_MENU: { - dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; - short choice_ind; - char *pchoice; + dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; + epicsEnum16 choice_ind; + char *pchoice; if (!pfield) { dbMsgCpy(pdbentry, "Field not found"); return message; } - choice_ind = *((short *) pdbentry->pfield); - if (!pdbMenu || choice_ind<0 || choice_ind>=pdbMenu->nChoice) + choice_ind = *((epicsEnum16 *) pdbentry->pfield); + if (!pdbMenu || choice_ind < 0 || choice_ind >= pdbMenu->nChoice) return NULL; pchoice = pdbMenu->papChoiceValue[choice_ind]; dbMsgCpy(pdbentry, pchoice); @@ -2072,9 +2086,9 @@ char *dbGetStringNum(DBENTRY *pdbentry) break; case DBF_DEVICE: { - dbDeviceMenu *pdbDeviceMenu; - char *pchoice; - short choice_ind; + dbDeviceMenu *pdbDeviceMenu; + epicsEnum16 choice_ind; + char *pchoice; if (!pfield) { dbMsgCpy(pdbentry, "Field not found"); @@ -2083,7 +2097,7 @@ char *dbGetStringNum(DBENTRY *pdbentry) pdbDeviceMenu = dbGetDeviceMenu(pdbentry); if (!pdbDeviceMenu) return NULL; - choice_ind = *((short *) pdbentry->pfield); + choice_ind = *((epicsEnum16 *) pdbentry->pfield); if (choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice) return NULL; pchoice = pdbDeviceMenu->papChoice[choice_ind]; @@ -2483,9 +2497,11 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring) case DBF_CHAR: case DBF_SHORT: case DBF_LONG: + case DBF_INT64: case DBF_UCHAR: case DBF_USHORT: case DBF_ULONG: + case DBF_UINT64: case DBF_ENUM: case DBF_FLOAT: case DBF_DOUBLE: @@ -2536,189 +2552,6 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring) return(status); } -char * dbVerify(DBENTRY *pdbentry,const char *pstring) -{ - dbFldDes *pflddes = pdbentry->pflddes; - char *message; - int stringHasMacro=FALSE; - - stringHasMacro = strstr(pstring,"$(") || strstr(pstring,"${"); - message = getpMessage(pdbentry); - if(!pflddes) {strcpy(message,"fldDes not found"); return(message);} - if(strstr(pstring,"$(") || strstr(pstring,"${")) return(NULL); - switch (pflddes->field_type) { - case DBF_STRING: { - size_t length; - - length=strlen(pstring); - if(length>=pflddes->size) { - sprintf(message,"string to big. max=%hd",pflddes->size); - return(message); - } - if((pflddes->special == SPC_CALC) && !stringHasMacro) { - char rpcl[RPCL_LEN]; - short err; - long status; - - status = postfix(pstring,rpcl,&err); - if(status) { - sprintf(message,"%s in CALC expression '%s'", - calcErrorStr(err), pstring); - return(message); - } - } - } - return(NULL); - case DBF_CHAR : - case DBF_SHORT : - case DBF_LONG:{ - long value; - char *endp; - - value = strtol(pstring,&endp,0); - if(*endp!=0) { - strcpy(message,"not an integer number"); - return(message); - } - switch (pflddes->field_type) { - case DBF_CHAR : - if(value<-128 || value>127) { - strcpy(message,"must have -128<=value<=127"); - return(message); - } - return(NULL); - case DBF_SHORT : - if(value<-32768 || value>32767) { - strcpy(message,"must have -32768<=value<=32767"); - return(message); - } - return(NULL); - case DBF_LONG : return(NULL); - default: - errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); - return(NULL); - } - } - case DBF_UCHAR: - case DBF_USHORT: - case DBF_ULONG: - case DBF_ENUM:{ - unsigned long value; - char *endp; - - if(strchr(pstring,'-')) { - strcpy(message,"not an unsigned number"); - return(message); - } - value = strtoul(pstring,&endp,0); - if(*endp!=0) { - strcpy(message,"not an integer number"); - return(message); - } - switch (pflddes->field_type) { - case DBF_UCHAR : - if(value>255) { - strcpy(message,"must have 0<=value<=255"); - return(message); - } - return(NULL); - case DBF_ENUM: - case DBF_USHORT : - if(value>65535) { - strcpy(message,"must have 0<=value<=65535"); - return(message); - } - return(NULL); - case DBF_ULONG : return(NULL); - default: - errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); - return(NULL); - } - } - case DBF_FLOAT: - case DBF_DOUBLE: { - char *endp; - - (void) epicsStrtod(pstring,&endp); - if(*endp!=0) { - strcpy(message,"not a number"); - return(message); - } - return(NULL); - } - case DBF_MENU: { - dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; - char *pchoice; - int i; - - if(!pdbMenu) return(NULL); - for (i = 0; i < pdbMenu->nChoice; i++) { - if(!(pchoice = pdbMenu->papChoiceValue[i])) continue; - if(strcmp(pchoice, pstring) == 0) { - return(NULL); - } - } - } - strcpy(message,"Not a valid menu choice"); - return (message); - case DBF_DEVICE: { - dbDeviceMenu *pdbDeviceMenu; - char *pchoice; - int i; - - pdbDeviceMenu = dbGetDeviceMenu(pdbentry); - if(!pdbDeviceMenu) return(NULL); - if(pdbDeviceMenu->nChoice == 0) return(NULL); - for (i = 0; i < pdbDeviceMenu->nChoice; i++) { - if (!(pchoice = pdbDeviceMenu->papChoice[i])) - continue; - if (strcmp(pchoice, pstring) == 0) { - return(NULL); - } - } - } - strcpy(message,"Not a valid menu choice"); - return (message); - case DBF_INLINK: - case DBF_OUTLINK: - case DBF_FWDLINK: - return(NULL); - default: break; - } - strcpy(message,"Not a valid field type"); - return (message); -} - -char *dbGetRange(DBENTRY *pdbentry) -{ - dbFldDes *pflddes = pdbentry->pflddes; - char *message; - - message = getpMessage(pdbentry); - if(!pflddes) {strcpy(message,"fldDes not found"); return(message);} - switch (pflddes->field_type) { - case DBF_STRING: {strcpy(message,"STRING"); return(message);} - case DBF_CHAR : {strcpy(message,"CHAR"); return(message);} - case DBF_SHORT : {strcpy(message,"SHORT");return(message);} - case DBF_LONG: {strcpy(message,"LONG"); return(message);} - case DBF_UCHAR: {strcpy(message,"UCHAR");return(message);} - case DBF_USHORT:{strcpy(message,"USHORT");return(message);} - case DBF_ULONG:{strcpy(message,"ULONG:");return(message);} - case DBF_ENUM: {strcpy(message,"ENUM");return(message);} - case DBF_FLOAT: {strcpy(message,"FLOAT");return(message);} - case DBF_DOUBLE: {strcpy(message,"DOUBLE");return(message);} - case DBF_MENU: {strcpy(message,"MENU");return(message);} - case DBF_DEVICE: {strcpy(message,"DEVICE");return(message);} - case DBF_INLINK: {strcpy(message,"INLINK");return(message);} - case DBF_OUTLINK: {strcpy(message,"OUTLINK");return(message);} - case DBF_FWDLINK: {strcpy(message,"FWDLINK");return(message);} - default: - errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); - } - strcpy(message,"Not a valid field type"); - return (message); -} - long dbFirstInfo(DBENTRY *pdbentry) { dbRecordNode *precnode = pdbentry->precnode; diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index 886fa3501..ebaa44346 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -119,6 +119,8 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) case DBF_USHORT: case DBF_LONG: case DBF_ULONG: + case DBF_INT64: + case DBF_UINT64: case DBF_FLOAT: case DBF_DOUBLE: case DBF_ENUM: @@ -204,277 +206,291 @@ int dbIsMacroOk(DBENTRY *pdbentry) { return(FALSE); } epicsShareFunc int dbIsDefaultValue(DBENTRY *pdbentry) { - dbFldDes *pflddes = pdbentry->pflddes; - void *pfield = pdbentry->pfield; + dbFldDes *pflddes = pdbentry->pflddes; + void *pfield = pdbentry->pfield; + + if (!pflddes || !pfield) + return FALSE; - if(!pflddes) return(FALSE); - if(!pfield) return(FALSE); switch (pflddes->field_type) { - case (DBF_STRING) : { - char *p = (char *)pfield; - - if(!pflddes->initial) return((strlen(p)==0) ? TRUE : FALSE); - return((strcmp(pflddes->initial,p)==0) ? TRUE : FALSE); - } - case DBF_CHAR: { - char field = *(char *)pfield; - long ltemp; - if(pflddes->initial) { - ltemp = strtol(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_UCHAR: { - unsigned char field = *(unsigned char *)pfield; - unsigned long ltemp; + case DBF_STRING: { + char *p = (char *)pfield; - if(pflddes->initial) { - ltemp = strtoul(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_SHORT: { - short field = *(short *)pfield; - long ltemp; + return pflddes->initial ? ! strcmp(pflddes->initial, p) + : ! strlen(p); + } + case DBF_CHAR: { + epicsInt8 field = *(epicsInt8 *)pfield; + epicsInt8 def; - if(pflddes->initial) { - ltemp = strtol(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_USHORT: { - unsigned short field = *(unsigned short *)pfield; - unsigned long ltemp; + if (!pflddes->initial) + return field == 0; - if(pflddes->initial) { - ltemp = strtoul(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_LONG: { - long field = *(long *)pfield; - long ltemp; + return ! epicsParseInt8(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_UCHAR: { + epicsUInt8 field = *(epicsUInt8 *)pfield; + epicsUInt8 def; - if(pflddes->initial) { - ltemp = strtol(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_ULONG: { - unsigned long field = *(unsigned long *)pfield; - unsigned long ltemp; + if (!pflddes->initial) + return field == 0; - if(pflddes->initial) { - ltemp = strtoul(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_FLOAT: { - float field = *(float *)pfield; - double dtemp; + return ! epicsParseUInt8(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_SHORT: { + epicsInt16 field = *(epicsInt16 *)pfield; + epicsInt16 def; - if(pflddes->initial) { - dtemp = epicsStrtod(pflddes->initial,NULL); - return((field==dtemp)); - } - return((field==0.0)); - } - case DBF_DOUBLE: { - double field = *(double *)pfield; - double dtemp; + if (!pflddes->initial) + return field == 0; - if(pflddes->initial) { - dtemp = epicsStrtod(pflddes->initial,NULL); - return((field==dtemp)); - } - return((field==0.0)); - } - case DBF_ENUM: { - unsigned short field = *(unsigned short *)pfield; - unsigned long ltemp; + return ! epicsParseInt16(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_ENUM: + case DBF_USHORT: { + epicsUInt16 field = *(epicsUInt16 *)pfield; + epicsUInt16 def; - if(pflddes->initial) { - ltemp = strtoul(pflddes->initial,NULL,0); - return((field==ltemp)); - } - return((field==0)); - } - case DBF_MENU: { - unsigned short field = *(unsigned short *)pfield; - long value; - char *endp; + if (!pflddes->initial) + return field == 0; - if(pflddes->initial) { - value = dbGetMenuIndexFromString(pdbentry,pflddes->initial); - if(value==-1) { - value = strtol(pflddes->initial,&endp,0); - if(*endp!='\0') return(FALSE); - } - } else { - value = 0; - } - if((unsigned short)value == field) return(TRUE); - return(FALSE); - } - case DBF_DEVICE: { - dbRecordType *precordType = pdbentry->precordType; + return ! epicsParseUInt16(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_LONG: { + epicsInt32 field = *(epicsInt32 *)pfield; + epicsInt32 def; - if(!precordType) { - epicsPrintf("dbIsDefaultValue: pdbRecordType is NULL??\n"); - return(FALSE); - } - if(ellCount(&precordType->devList)==0) return(TRUE); - return(FALSE); - } - case DBF_INLINK: - case DBF_OUTLINK: - case DBF_FWDLINK: { - struct link *plink = (struct link *)pfield; + if (!pflddes->initial) + return field == 0; - if(!plink) return(FALSE); - if(plink->type!=CONSTANT) return(FALSE); - if(plink->value.constantStr == 0) return(TRUE); - if(!pflddes->initial) return(FALSE); - if(strcmp(plink->value.constantStr,pflddes->initial)==0) - return(TRUE); - return(FALSE); - } - default: - return(TRUE); + return ! epicsParseInt32(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_ULONG: { + epicsUInt32 field = *(epicsUInt32 *)pfield; + epicsUInt32 def; + + if (!pflddes->initial) + return field == 0; + + return ! epicsParseUInt32(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_INT64: { + epicsInt64 field = *(epicsInt64 *)pfield; + epicsInt64 def; + + if (!pflddes->initial) + return field == 0; + + return ! epicsParseInt64(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_UINT64: { + epicsUInt64 field = *(epicsUInt64 *)pfield; + epicsUInt64 def; + + if (!pflddes->initial) + return field == 0; + + return ! epicsParseUInt64(pflddes->initial, &def, 0, NULL) + && field == def; + } + case DBF_FLOAT: { + epicsFloat32 field = *(epicsFloat32 *)pfield; + epicsFloat32 def; + + if (!pflddes->initial) + return field == 0; + + return ! epicsParseFloat32(pflddes->initial, &def, NULL) + && field == def; + } + case DBF_DOUBLE: { + epicsFloat64 field = *(epicsFloat64 *)pfield; + epicsFloat64 def; + + if (!pflddes->initial) + return field == 0; + + return ! epicsParseFloat64(pflddes->initial, &def, NULL) + && field == def; + } + case DBF_MENU: { + epicsEnum16 field = *(epicsEnum16 *)pfield; + epicsEnum16 def; + int index; + + if (!pflddes->initial) + return field == 0; + + index = dbGetMenuIndexFromString(pdbentry, pflddes->initial); + if (index < 0) { + if (epicsParseUInt16(pflddes->initial, &def, 0, NULL)) + return FALSE; + } + else + def = index; + return field == def; + } + case DBF_DEVICE: { + dbRecordType *precordType = pdbentry->precordType; + + if (!precordType) { + epicsPrintf("dbIsDefaultValue: pdbRecordType is NULL??\n"); + return FALSE; + } + return ellCount(&precordType->devList) == 0; + } + case DBF_INLINK: + case DBF_OUTLINK: + case DBF_FWDLINK: { + struct link *plink = (struct link *)pfield; + + if (!plink || plink->type != CONSTANT) + return FALSE; + + /* These conditions don't make a lot of sense... */ + if (!plink->value.constantStr) + return TRUE; + + if (!pflddes->initial) /* Default value for a link field? */ + return FALSE; + + return !strcmp(plink->value.constantStr, pflddes->initial); + } + default: + return TRUE; } - return(FALSE); } -long dbPutStringNum(DBENTRY *pdbentry,const char *pstring) +long dbPutStringNum(DBENTRY *pdbentry, const char *pstring) { - dbFldDes *pflddes = pdbentry->pflddes; - void *pfield = pdbentry->pfield; - long status=0; + dbFldDes *pflddes = pdbentry->pflddes; + void *pfield = pdbentry->pfield; + + if (!pfield) + return S_dbLib_fieldNotFound; - if(!pfield) return(S_dbLib_fieldNotFound); switch (pflddes->field_type) { - case DBF_CHAR : - case DBF_SHORT : - case DBF_LONG:{ - long value; - char *endp; + case DBF_CHAR: + return epicsParseInt8(pstring, pfield, 0, NULL); - value = strtol(pstring,&endp,0); - if(*endp!=0) status = S_dbLib_badField; - switch (pflddes->field_type) { - case DBF_CHAR : *(char *)pfield = (char)value; break; - case DBF_SHORT : *(short *)pfield = (short)value; break; - case DBF_LONG : *(epicsInt32 *)pfield = (epicsInt32)value; break; - default: epicsPrintf("Logic error in dbPutStringNum\n"); - } - } - break; case DBF_UCHAR: + return epicsParseUInt8(pstring, pfield, 0, NULL); + + case DBF_SHORT: + return epicsParseInt16(pstring, pfield, 0, NULL); + case DBF_USHORT: + case DBF_ENUM: + return epicsParseUInt16(pstring, pfield, 0, NULL); + + case DBF_LONG: + return epicsParseInt32(pstring, pfield, 0, NULL); + case DBF_ULONG: - case DBF_ENUM:{ - unsigned long value; - char *endp; + return epicsParseUInt32(pstring, pfield, 0, NULL); + + case DBF_INT64: + return epicsParseInt64(pstring, pfield, 0, NULL); + + case DBF_UINT64: + return epicsParseUInt64(pstring, pfield, 0, NULL); - value = strtoul(pstring,&endp,0); - if(*endp!=0) status = S_dbLib_badField; - switch (pflddes->field_type) { - case DBF_UCHAR : *(unsigned char *)pfield = (unsigned char)value; break; - case DBF_USHORT: - case DBF_ENUM: *(unsigned short *)pfield = (unsigned short)value; break; - case DBF_ULONG : *(epicsUInt32 *)pfield = (epicsUInt32)value; break; - default: epicsPrintf("Logic error in dbPutStringNum\n"); - } - } - break; case DBF_FLOAT: - case DBF_DOUBLE: { - double value; - char *endp; + return epicsParseFloat32(pstring, pfield, NULL); + + case DBF_DOUBLE: + return epicsParseFloat64(pstring, pfield, NULL); - value = epicsStrtod(pstring,&endp); - if(*endp!=0) status = S_dbLib_badField; - if(pflddes->field_type == DBF_FLOAT) - *(float *)pfield = (float)value; - else - *(double *)pfield = value; - } - break; case DBF_MENU: - case DBF_DEVICE: {/*Must allow value that is choice or index*/ - unsigned short *field= (unsigned short*)pfield; - int ind; - long value; - char *endp; + case DBF_DEVICE: { + epicsEnum16 *field = (epicsEnum16 *) pfield; + int index = dbGetMenuIndexFromString(pdbentry, pstring); + + if (index < 0) { + epicsEnum16 value; + long status = epicsParseUInt16(pstring, &value, 0, NULL); + + if (status) + return status; + + index = dbGetNMenuChoices(pdbentry); + if (value > index && index > 0) + return S_dbLib_badField; + + *field = value; + } + else + *field = index; + return 0; + } - ind = dbGetMenuIndexFromString(pdbentry,pstring); - if(ind==-1) { - value = strtol(pstring,&endp,0); - if(*endp!='\0') return(S_dbLib_badField); - ind = value; - /*Check that ind is withing range*/ - if(!dbGetMenuStringFromIndex(pdbentry,ind)) - return(S_dbLib_badField); - } - *field = (unsigned short)ind; - } - return (0); default: - return (S_dbLib_badField); + return S_dbLib_badField; } - return(status); } - + epicsShareFunc int dbGetMenuIndex(DBENTRY *pdbentry) { - dbFldDes *pflddes = pdbentry->pflddes; - void *pfield = pdbentry->pfield; + dbFldDes *pflddes = pdbentry->pflddes; + void *pfield = pdbentry->pfield; + + if (!pflddes || !pfield) + return -1; - if(!pflddes) return(-1); - if(!pfield) return(-1); switch (pflddes->field_type) { - case (DBF_MENU): - case (DBF_DEVICE): - return((int)(*(unsigned short *)pfield)); - default: - errPrintf(-1,__FILE__, __LINE__,"Logic Error\n"); + case DBF_MENU: + case DBF_DEVICE: + return * (epicsEnum16 *) pfield; + default: + epicsPrintf("dbGetMenuIndex: Called for field type %d\n", + pflddes->field_type); } - return(-1); + return -1; } - -epicsShareFunc long dbPutMenuIndex(DBENTRY *pdbentry,int index) -{ - dbFldDes *pflddes = pdbentry->pflddes; - unsigned short *pfield = pdbentry->pfield; - if(!pflddes) return(S_dbLib_flddesNotFound); - if(!pfield) return(S_dbLib_fieldNotFound); +epicsShareFunc long dbPutMenuIndex(DBENTRY *pdbentry, int index) +{ + dbFldDes *pflddes = pdbentry->pflddes; + epicsEnum16 *pfield = pdbentry->pfield; + + if (!pflddes) + return S_dbLib_flddesNotFound; + if (!pfield) + return S_dbLib_fieldNotFound; + switch (pflddes->field_type) { case DBF_MENU: { - dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; + dbMenu *pdbMenu = (dbMenu *) pflddes->ftPvt; - if(!pdbMenu) return(S_dbLib_menuNotFound); - if(index<0 || index>=pdbMenu->nChoice) return(S_dbLib_badField); - *pfield = (unsigned short)index; - return(0); - } - case DBF_DEVICE: { - dbDeviceMenu *pdbDeviceMenu; + if (!pdbMenu) + return S_dbLib_menuNotFound; + if (index < 0 || index >= pdbMenu->nChoice) + return S_dbLib_badField; - pdbDeviceMenu = dbGetDeviceMenu(pdbentry); - if(!pdbDeviceMenu) return(S_dbLib_menuNotFound); - if(index<0 || index>=pdbDeviceMenu->nChoice) - return(S_dbLib_badField); - return(dbPutString(pdbentry,pdbDeviceMenu->papChoice[index])); - } - default: - break; + *pfield = index; + return 0; } - return (S_dbLib_badField); + + case DBF_DEVICE: { + dbDeviceMenu *pdbDeviceMenu = dbGetDeviceMenu(pdbentry); + + if (!pdbDeviceMenu) + return S_dbLib_menuNotFound; + if (index < 0 || index >= pdbDeviceMenu->nChoice) + return S_dbLib_badField; + + return dbPutString(pdbentry, pdbDeviceMenu->papChoice[index]); + } + + default: + break; + } + return S_dbLib_badField; } diff --git a/src/libCom/cvtFast/cvtFast.c b/src/libCom/cvtFast/cvtFast.c index 2f29dd51f..3fb6a3d05 100644 --- a/src/libCom/cvtFast/cvtFast.c +++ b/src/libCom/cvtFast/cvtFast.c @@ -1,73 +1,62 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* Very efficient routines to convert numbers to strings - * Author: Bob Dalesio wrote cvtFloatToString (called FF_TO_STR) - * Code is same for cvtDoubleToString - * Marty Kraimer wrote cvtCharToString,cvtUcharToString - * cvtShortToString,cvtUshortToString, - * cvtLongToString, and cvtUlongToString - * Mark Anderson wrote cvtLongToHexString, cvtLongToOctalString, - * adopted cvt[Float/Double]ExpString and - * cvt[Float/Double]CompactString from fToEStr - * and fixed calls to gcvt - * - * Date: 12 January 1993 +/* Fast numeric to string conversions * + * Original Authors: + * Bob Dalesio, Mark Anderson and Marty Kraimer + * Date: 12 January 1993 */ -#include -#include -#include -#include /* XPG2/XPG3/POSIX.1/FIPS151-1/ANSI-C */ +#include +#include #define epicsExportSharedSymbols #include "cvtFast.h" #include "epicsMath.h" - -/* - * This routine converts numbers less than 10,000,000. It defers to f_to_str for - * numbers requiring more than 8 places of precision. There are only eight decimal - */ -static epicsInt32 frac_multiplier[] = - {1,10,100,1000,10000,100000,1000000,10000000,100000000}; +#include "epicsStdio.h" -int epicsShareAPI cvtFloatToString( - float flt_value, - char *pstr_value, - unsigned short precision) +/* + * These routines convert numbers up to +/- 10,000,000. + * They defer to sprintf() for numbers requiring more than + * 8 places of precision. + */ +static epicsInt32 frac_multiplier[] = + {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; + +int cvtFloatToString(float flt_value, char *pdest, + epicsUInt16 precision) { - unsigned short got_one,i; - epicsInt32 whole,iplace,number,fraction,fplace; + int got_one, i; + epicsInt32 whole, iplace, number, fraction, fplace; float ftemp; char *startAddr; /* can this routine handle this conversion */ if (isnan(flt_value) || precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) { - sprintf(pstr_value,"%12.5e",(double)flt_value); - return((int)strlen(pstr_value)); + sprintf(pdest,"%12.5e",(double)flt_value); + return((int)strlen(pdest)); } - startAddr = pstr_value; + startAddr = pdest; /* determine the sign */ if (flt_value < 0){ - *pstr_value++ = '-'; + *pdest++ = '-'; flt_value = -flt_value; }; - /* remove the whole number portion */ + /* remove the whole number portion */ whole = (epicsInt32)flt_value; ftemp = flt_value - whole; /* multiplier to convert fractional portion to integer */ fplace = frac_multiplier[precision]; - fraction = (epicsInt32)(ftemp * fplace * 10); + fraction = (epicsInt32)(ftemp * fplace * 10); fraction = (fraction + 5) / 10; /* round up */ /* determine rounding into the whole number portion */ @@ -83,41 +72,41 @@ int epicsShareAPI cvtFloatToString( got_one = 1; number = whole / iplace; whole = whole - (number * iplace); - *pstr_value = number + '0'; - pstr_value++; + *pdest = number + '0'; + pdest++; }else if (got_one){ - *pstr_value = '0'; - pstr_value++; + *pdest = '0'; + pdest++; } } if (!got_one){ - *pstr_value = '0'; - pstr_value++; + *pdest = '0'; + pdest++; } /* fraction */ if (precision > 0){ /* convert fractional portional to ASCII */ - *pstr_value = '.'; - pstr_value++; + *pdest = '.'; + pdest++; for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){ number = fraction / fplace; fraction -= number * fplace; - *pstr_value = number + '0'; - pstr_value++; + *pdest = number + '0'; + pdest++; } } - *pstr_value = 0; + *pdest = 0; - return((int)(pstr_value - startAddr)); + return((int)(pdest - startAddr)); } - -int epicsShareAPI cvtDoubleToString( + +int cvtDoubleToString( double flt_value, - char *pstr_value, - unsigned short precision) + char *pdest, + epicsUInt16 precision) { - unsigned short got_one,i; + epicsUInt16 got_one,i; epicsInt32 whole,iplace,number,fraction,fplace; double ftemp; char *startAddr; @@ -126,23 +115,23 @@ int epicsShareAPI cvtDoubleToString( if (isnan(flt_value) || precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) { if (precision > 8 || flt_value > 1e16 || flt_value < -1e16) { if(precision>17) precision=17; - sprintf(pstr_value,"%*.*e",precision+7,precision, + sprintf(pdest,"%*.*e",precision+7,precision, flt_value); } else { if(precision>3) precision=3; - sprintf(pstr_value,"%.*f",precision,flt_value); + sprintf(pdest,"%.*f",precision,flt_value); } - return((int)strlen(pstr_value)); + return((int)strlen(pdest)); } - startAddr = pstr_value; + startAddr = pdest; /* determine the sign */ if (flt_value < 0){ - *pstr_value++ = '-'; + *pdest++ = '-'; flt_value = -flt_value; }; - /* remove the whole number portion */ + /* remove the whole number portion */ whole = (epicsInt32)flt_value; ftemp = flt_value - whole; @@ -164,432 +153,364 @@ int epicsShareAPI cvtDoubleToString( got_one = 1; number = whole / iplace; whole = whole - (number * iplace); - *pstr_value = number + '0'; - pstr_value++; + *pdest = number + '0'; + pdest++; }else if (got_one){ - *pstr_value = '0'; - pstr_value++; + *pdest = '0'; + pdest++; } } if (!got_one){ - *pstr_value = '0'; - pstr_value++; + *pdest = '0'; + pdest++; } /* fraction */ if (precision > 0){ /* convert fractional portional to ASCII */ - *pstr_value = '.'; - pstr_value++; + *pdest = '.'; + pdest++; for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){ number = fraction / fplace; fraction -= number * fplace; - *pstr_value = number + '0'; - pstr_value++; + *pdest = number + '0'; + pdest++; } } - *pstr_value = 0; + *pdest = 0; - return((int)(pstr_value - startAddr)); + return((int)(pdest - startAddr)); } +/* + * These routines are provided for backwards compatibility, + * extensions such as MEDM, edm and histtool use them. + */ + /* * cvtFloatToExpString * - * converts floating point numbers to E-format NULL terminated strings + * Converts a float to a %e formatted string */ -int epicsShareAPI cvtFloatToExpString( - float f_value, - char *pstr_value, - unsigned short f_precision) +int cvtFloatToExpString(float val, char *pdest, epicsUInt16 precision) { - /*sunos uses char*sprint as function prototype*/ - sprintf(pstr_value,"%.*e",(int)f_precision,(double)f_value); - return((int)strlen(pstr_value)); + return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val); } /* * cvtFloatToCompactString * - * Converts floating point numbers to %g format NULL terminated strings, - * resulting in the most "compact" expression of the value - * ("f" notation if 10-4 < |value| < 10+4, otherwise "e" notation) + * Converts a float to a %g formatted string. + * The result uses %f notation for 10e-4 < |value| < 10e+4, + * otherwise %e notation. */ -int epicsShareAPI cvtFloatToCompactString( - float f_value, - char *pstr_value, - unsigned short f_precision ) +int cvtFloatToCompactString(float val, char *pdest, epicsUInt16 precision) { - if ((f_value < 1.e4 && f_value > 1.e-4) || - (f_value > -1.e4 && f_value < -1.e-4) || f_value == 0.0) { - return(cvtFloatToString(f_value,pstr_value,f_precision)); - } else { - return(cvtFloatToExpString(f_value,pstr_value,f_precision)); - } -} + if ((val < 1.e4 && val > 1.e-4) || + (val > -1.e4 && val < -1.e-4) || + val == 0.0) + return cvtFloatToString(val, pdest, precision); + return cvtFloatToExpString(val, pdest, precision); +} /* * cvtDoubleToExpString * - * converts double precision floating point numbers to E-format NULL - * terminated strings + * Converts a double to a %e formatted string */ -int epicsShareAPI cvtDoubleToExpString( - double f_value, - char *pstr_value, - unsigned short f_precision ) +int cvtDoubleToExpString(double val, char *pdest, epicsUInt16 precision) { - sprintf(pstr_value,"%.*e",(int)f_precision,f_value); - return((int)strlen(pstr_value)); + return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val); } /* * cvtDoubleToCompactString * - * Converts double precision floating point numbers to %g format NULL - * terminated strings, resulting in the most "compact" expression - * of the value ("f" notation if 10-4 < |value| < 10+4, otherwise - * "e" notation) + * Converts a double to %g formatted string. + * The result uses %f notation for 10e-4 < |value| < 10e+4, + * otherwise %e notation. */ -int epicsShareAPI cvtDoubleToCompactString( - double f_value, - char *pstr_value, - unsigned short f_precision ) +int cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 precision) { - if ((f_value < 1.e4 && f_value > 1.e-4) || - (f_value > -1.e4 && f_value < -1.e-4) || f_value == 0.0) { - return(cvtDoubleToString(f_value,pstr_value,f_precision)); - } else { - return(cvtDoubleToExpString(f_value,pstr_value,f_precision)); - } + if ((val < 1.e4 && val > 1.e-4) || + (val > -1.e4 && val < -1.e-4) || + val == 0.0) + return cvtDoubleToString(val, pdest, precision); + + return cvtDoubleToExpString(val, pdest, precision); } - -/* Convert various integer types to ascii */ -static char digit_to_ascii[10]={'0','1','2','3','4','5','6','7','8','9'}; -int epicsShareAPI cvtCharToString( - signed char source, - char *pdest) +/* Integer conversion primitives */ + +static size_t + UInt32ToDec(epicsUInt32 val, char *pdest) { - unsigned char val,temp; - char digit[3]; - int i,j; - char *startAddr = pdest; + int i; + char digit[10]; + size_t len; - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); - } - if(source<0) { - if(source == CHAR_MIN) { - sprintf(pdest,"%d",CHAR_MIN); - return((int)strlen(pdest)); - } - *pdest++ = '-'; - source = -source; - } - val = source; - for(i=0; val!=0; i++) { - temp = val/10; - digit[i] = digit_to_ascii[val - temp*10]; - val = temp; - } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; + for (i = 0; val; i++) { + epicsUInt32 tenth = val / 10; + + digit[i] = val - tenth * 10 + '0'; + val = tenth; } + len = i; + + while (i > 0) + *pdest++ = digit[--i]; + *pdest = 0; - return((int)(pdest-startAddr)); + return len; } - -int epicsShareAPI cvtUcharToString( - unsigned char source, - char *pdest) +static size_t + UInt32ToBase(epicsUInt32 val, char *pdest, int base) { - unsigned char val,temp; - char digit[3]; - int i,j; - char *startAddr = pdest; + int i; + char digit, digits[32]; + size_t len; - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); - } - val = source; - for(i=0; val!=0; i++) { - temp = val/10; - digit[i] = digit_to_ascii[val - temp*10]; - val = temp; - } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; + for (i = 0; val; i++) { + epicsUInt32 tenth = val / base; + + digit = val - tenth * base; + digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a'; + val = tenth; } + len = i; + + while (i > 0) + *pdest++ = digits[--i]; + *pdest = 0; - return((int)(pdest-startAddr)); + return len; } - -int epicsShareAPI cvtShortToString( - short source, - char *pdest) +static size_t + UInt64ToDec(epicsUInt64 val, char *pdest) { - short val,temp; - char digit[6]; - int i,j; - char *startAddr = pdest; + int i; + char digit[20]; + size_t len; - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); - } - if(source<0) { - if(source == SHRT_MIN) { - sprintf(pdest,"%d",SHRT_MIN); - return((int)(strlen(pdest))); - } - *pdest++ = '-'; - source = -source; - } - val = source; - for(i=0; val!=0; i++) { - temp = val/10; - digit[i] = digit_to_ascii[val - temp*10]; - val = temp; - } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; + for (i = 0; val; i++) { + epicsUInt64 tenth = val / 10; + + digit[i] = val - tenth * 10 + '0'; + val = tenth; } + + len = i; + while (i > 0) + *pdest++ = digit[--i]; + *pdest = 0; - return((int)(pdest-startAddr)); + return len; } - -int epicsShareAPI cvtUshortToString( - unsigned short source, - char *pdest) +static size_t + UInt64ToBase(epicsUInt64 val, char *pdest, int base) { - unsigned short val,temp; - char digit[5]; - int i,j; - char *startAddr = pdest; + int i; + char digit, digits[64]; + size_t len; - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); - } - val = source; - for(i=0; val!=0; i++) { - temp = val/10; - digit[i] = digit_to_ascii[val - temp*10]; - val = temp; - } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; + for (i = 0; val; i++) { + epicsUInt64 tenth = val / base; + + digit = val - tenth * base; + digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a'; + val = tenth; } + len = i; + + while (i > 0) + *pdest++ = digits[--i]; + *pdest = 0; - return((int)(pdest-startAddr)); + return len; } -int epicsShareAPI cvtLongToString( - epicsInt32 source, - char *pdest) -{ - epicsInt32 val,temp; - char digit[11]; - int i,j; - char *startAddr = pdest; +/* Integer conversion routines */ - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); +size_t + cvtUInt32ToString(epicsUInt32 val, char *pdest) +{ + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 1; } - if(source<0) { - if(source == INT_MIN) { - sprintf(pdest,"%d",source); - return((int)strlen(pdest)); - } - *pdest++ = '-'; - source = -source; + + return UInt32ToDec(val, pdest); +} + +size_t + cvtInt32ToString(epicsInt32 val, char *pdest) +{ + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 1; } - val = source; - for(i=0; val!=0; i++) { - temp = val/10; - digit[i] = digit_to_ascii[val - temp*10]; - val = temp; + + if (val > 0) + return UInt32ToDec(val, pdest); + + if (val == -0x80000000) { + strcpy(pdest, "-2147483648"); + return strlen(pdest); } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; - } - *pdest = 0; - return((int)(pdest-startAddr)); + + *pdest++ = '-'; + return 1 + UInt32ToDec(-val, pdest); } -int epicsShareAPI cvtUlongToString( - epicsUInt32 source, - char *pdest) +size_t + cvtUInt64ToString(epicsUInt64 val, char *pdest) { - epicsUInt32 val,temp; - char digit[10]; - int i,j; - char *startAddr = pdest; + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 1; + } - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); + return UInt64ToDec(val, pdest); +} + +size_t + cvtInt64ToString(epicsInt64 val, char *pdest) +{ + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 1; } - val = source; - for(i=0; val!=0; i++) { - temp = val/10; - digit[i] = digit_to_ascii[val - temp*10]; - val = temp; + + if (val > 0) + return UInt64ToDec(val, pdest); + + if (val == -0x8000000000000000LL) { + strcpy(pdest, "-9223372036854775808"); + return strlen(pdest); } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; - } - *pdest = 0; - return((int)(pdest-startAddr)); + + *pdest++ = '-'; + return 1 + UInt64ToDec(-val, pdest); } -/* Convert hex digits to ascii */ - -static char hex_digit_to_ascii[16]={'0','1','2','3','4','5','6','7','8','9', - 'a','b','c','d','e','f'}; - - -int epicsShareAPI cvtLongToHexString( - epicsInt32 source, - char *pdest) +size_t + cvtInt32ToHexString(epicsInt32 val, char *pdest) { - epicsInt32 val,temp; - char digit[10]; - int i,j; - char *startAddr = pdest; + if (val < 0) + *pdest++ = '-'; - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); - } - if(source<0) { - if(source == INT_MIN) { - sprintf(pdest,"-0x%x",source); - return((int)strlen(pdest)); - } - *pdest++ = '-'; - source = -source; - } - *pdest++ = '0'; *pdest++ = 'x'; - val = source; - for(i=0; val!=0; i++) { - temp = val/16; - digit[i] = hex_digit_to_ascii[val - temp*16]; - val = temp; - } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; - } - *pdest = 0; - return((int)(pdest-startAddr)); -} - - -int epicsShareAPI cvtLongToOctalString( - epicsInt32 source, - char *pdest) -{ - epicsInt32 val,temp; - char digit[16]; - int i,j; - char *startAddr = pdest; - - if(source==0) { - *pdest++ = '0'; - *pdest = 0; - return((int)(pdest-startAddr)); - } - if(source<0) { - if(source == INT_MIN) { - sprintf(pdest,"-0%o",source); - return((int)strlen(pdest)); - } - *pdest++ = '-'; - source = -source; - } *pdest++ = '0'; - val = source; - for(i=0; val!=0; i++) { - temp = val/8; - /* reuse digit_to_ascii since octal is a subset of decimal */ - digit[i] = digit_to_ascii[val - temp*8]; - val = temp; + *pdest++ = 'x'; + + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 3; } - for(j=i-1; j>=0; j--) { - *pdest++ = digit[j]; + + if (val > 0) + return 2 + UInt32ToBase(val, pdest, 16); + + if (val == -0x80000000) { + strcpy(pdest, "80000000"); + return 11; } - *pdest = 0; - return((int)(pdest-startAddr)); + + return 3 + UInt32ToBase(-val, pdest, 16); } - - - -/* - * - * cvtBitsToUlong() - * - * extract a bit field from the source epicsUInt32 - */ -epicsUInt32 epicsShareAPI cvtBitsToUlong( -epicsUInt32 src, -unsigned bitFieldOffset, -unsigned bitFieldLength) +size_t + cvtUInt32ToHexString(epicsUInt32 val, char *pdest) { - epicsUInt32 mask; + *pdest++ = '0'; + *pdest++ = 'x'; - src = src >> bitFieldOffset; + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 3; + } - mask = (1< 0) { + *pdest++ = '0'; + return 1 + UInt32ToBase(val, pdest, 8); + } - return dest; + if (val == -0x80000000) { + strcpy(pdest, "-020000000000"); + return strlen(pdest); + } + + *pdest++ = '-'; + *pdest++ = '0'; + return 2 + UInt32ToBase(-val, pdest, 8); } + +size_t + cvtInt64ToHexString(epicsInt64 val, char *pdest) +{ + if (val < 0) + *pdest++ = '-'; + + *pdest++ = '0'; + *pdest++ = 'x'; + + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 3; + } + + if (val > 0) + return 2 + UInt64ToBase(val, pdest, 16); + + if (val == -0x8000000000000000LL) { + strcpy(pdest, "8000000000000000"); + return 19; + } + + return 3 + UInt64ToBase(-val, pdest, 16); +} + +size_t + cvtUInt64ToHexString(epicsUInt64 val, char *pdest) +{ + *pdest++ = '0'; + *pdest++ = 'x'; + + if (val == 0) { + *pdest++ = '0'; + *pdest = 0; + return 3; + } + + return 2 + UInt64ToBase(val, pdest, 16); +} + diff --git a/src/libCom/cvtFast/cvtFast.h b/src/libCom/cvtFast/cvtFast.h index d2eb86ddf..db06dda53 100644 --- a/src/libCom/cvtFast/cvtFast.h +++ b/src/libCom/cvtFast/cvtFast.h @@ -1,30 +1,23 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* - * Very efficient routines to convert numbers to strings + * Fast numeric to string conversions * - * Author: Bob Dalesio wrote cvtFloatToString (called FF_TO_STR) - * Code is same for cvtDoubleToString - * Marty Kraimer wrote cvtCharToString,cvtUcharToString - * cvtShortToString,cvtUshortToString, - * cvtLongToString, and cvtUlongToString - * Mark Anderson wrote cvtLongToHexString, cvtLongToOctalString, - * adopted cvt[Float/Double]ExpString and - * cvt[Float/Double]CompactString from fToEStr - * and fixed calls to gcvt - * Date: 12-9-92 + * Original Authors: + * Bob Dalesio, Mark Anderson and Marty Kraimer + * Date: 12 January 1993 */ + #ifndef INCcvtFasth #define INCcvtFasth -#include +#include #include "epicsTypes.h" #include "shareLib.h" @@ -34,46 +27,54 @@ extern "C" { #endif /* - * each of these functions return the number of characters "transmitted" - * (as in ANSI-C/POSIX.1/XPG3 sprintf() functions) + * All functions return the number of characters in the output */ -epicsShareFunc int epicsShareAPI - cvtFloatToString(float value, char *pstring, unsigned short precision); -epicsShareFunc int epicsShareAPI - cvtDoubleToString(double value, char *pstring, unsigned short precision); -epicsShareFunc int epicsShareAPI - cvtFloatToExpString(float value, char *pstring, unsigned short precision); -epicsShareFunc int epicsShareAPI - cvtDoubleToExpString(double value, char *pstring, unsigned short precision); -epicsShareFunc int epicsShareAPI - cvtFloatToCompactString(float value, char *pstring, unsigned short precision); -epicsShareFunc int epicsShareAPI - cvtDoubleToCompactString(double value, char *pstring, unsigned short precision); -epicsShareFunc int epicsShareAPI - cvtCharToString(signed char value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtUcharToString(unsigned char value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtShortToString(short value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtUshortToString(unsigned short value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtLongToString(epicsInt32 value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtUlongToString(epicsUInt32 value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtLongToHexString(epicsInt32 value, char *pstring); -epicsShareFunc int epicsShareAPI - cvtLongToOctalString(epicsInt32 value, char *pstring); -epicsShareFunc epicsUInt32 epicsShareAPI cvtBitsToUlong( - epicsUInt32 src, - unsigned bitFieldOffset, - unsigned bitFieldLength); -epicsShareFunc epicsUInt32 epicsShareAPI cvtUlongToBits( - epicsUInt32 src, - epicsUInt32 dest, - unsigned bitFieldOffset, - unsigned bitFieldLength); +epicsShareFunc int + cvtFloatToString(float val, char *pdest, epicsUInt16 prec); +epicsShareFunc int + cvtDoubleToString(double val, char *pdest, epicsUInt16 prec); + +epicsShareFunc int + cvtFloatToExpString(float val, char *pdest, epicsUInt16 prec); +epicsShareFunc int + cvtDoubleToExpString(double val, char *pdest, epicsUInt16 prec); +epicsShareFunc int + cvtFloatToCompactString(float val, char *pdest, epicsUInt16 prec); +epicsShareFunc int + cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 prec); + +epicsShareFunc size_t + cvtInt32ToString(epicsInt32 val, char *pdest); +epicsShareFunc size_t + cvtUInt32ToString(epicsUInt32 val, char *pdest); +epicsShareFunc size_t + cvtInt64ToString(epicsInt64 val, char *pdest); +epicsShareFunc size_t + cvtUInt64ToString(epicsUInt64 val, char *pdest); + +epicsShareFunc size_t + cvtInt32ToHexString(epicsInt32 val, char *pdest); +epicsShareFunc size_t + cvtUInt32ToHexString(epicsUInt32 val, char *pdest); +epicsShareFunc size_t + cvtInt32ToOctalString(epicsInt32 val, char *pdest); +epicsShareFunc size_t + cvtInt64ToHexString(epicsInt64 val, char *pdest); +epicsShareFunc size_t + cvtUInt64ToHexString(epicsUInt64 val, char *pdest); + +/* Support the original names */ + +#define cvtCharToString(val, str) cvtInt32ToString(val, str) +#define cvtUcharToString(val, str) cvtUInt32ToString(val, str) +#define cvtShortToString(val, str) cvtInt32ToString(val, str) +#define cvtUshortToString(val, str) cvtUInt32ToString(val, str) +#define cvtLongToString(val, str) cvtInt32ToString(val, str) +#define cvtUlongToString(val, str) cvtUInt32ToString(val, str) + +#define cvtLongToHexString(val, str) cvtInt32ToHexString(val, str) +#define cvtULongToHexString(val, str) cvtUInt32ToHexString(val, str) +#define cvtLongToOctalString(val, str) cvtInt32ToOctalString(val, str) #ifdef __cplusplus } diff --git a/src/libCom/misc/epicsStdlib.c b/src/libCom/misc/epicsStdlib.c index 865c8069d..f4348981b 100644 --- a/src/libCom/misc/epicsStdlib.c +++ b/src/libCom/misc/epicsStdlib.c @@ -256,7 +256,7 @@ epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units) return S_stdlib_overflow; #endif - *to = value; + *to = (epicsInt32) value; return 0; } @@ -274,7 +274,7 @@ epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units) return S_stdlib_overflow; #endif - *to = value; + *to = (epicsUInt32) value; return 0; } @@ -292,7 +292,7 @@ epicsParseInt64(const char *str, epicsInt64 *to, int base, char **units) if (status) return status; - *to = value; + *to = (epicsInt64) value; return 0; } @@ -310,7 +310,7 @@ epicsParseUInt64(const char *str, epicsUInt64 *to, int base, char **units) if (status) return status; - *to = value; + *to = (epicsUInt64) value; return 0; } diff --git a/src/libCom/osi/os/vxWorks/README b/src/libCom/osi/os/vxWorks/README deleted file mode 100644 index bbc0046b3..000000000 --- a/src/libCom/osi/os/vxWorks/README +++ /dev/null @@ -1,3 +0,0 @@ - -The source files here are vxWorks dependent. - diff --git a/src/libCom/osi/os/vxWorks/osdStrtod.h b/src/libCom/osi/os/vxWorks/osdStrtod.h index f2c5b68a9..91c47d70e 100644 --- a/src/libCom/osi/os/vxWorks/osdStrtod.h +++ b/src/libCom/osi/os/vxWorks/osdStrtod.h @@ -1,11 +1,11 @@ /*************************************************************************\ * Copyright (c) 2002 The University of Saskatchewan * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* - * This header is included as part of epicsString.h and epicsStdlib.h + * This header is included by epicsString.h and epicsStdlib.h */ #ifdef __cplusplus @@ -15,7 +15,7 @@ extern "C" { /* * epicsStrtod() for systems with broken strtod() routine */ -epicsShareFunc double epicsStrtod(const char *str, char **endp); +double epicsStrtod(const char *str, char **endp); /* * VxWorks doesn't provide these routines, so for now we do diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 6de92321e..0d84d85b2 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -176,6 +176,11 @@ macDefExpandTest_SRCS += macDefExpandTest.c testHarness_SRCS += macDefExpandTest.c TESTS += macDefExpandTest +TESTPROD_HOST += cvtFastTest +cvtFastTest_SRCS += cvtFastTest.cpp +testHarness_SRCS += cvtFastTest.cpp +TESTS += cvtFastTest + TESTPROD_HOST += macLibTest macLibTest_SRCS += macLibTest.c testHarness_SRCS += macLibTest.c diff --git a/src/libCom/test/cvtFastTest.c b/src/libCom/test/cvtFastTest.c new file mode 100644 index 000000000..48c14d02e --- /dev/null +++ b/src/libCom/test/cvtFastTest.c @@ -0,0 +1,457 @@ +/*************************************************************************\ +* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* cvtFastTest.c + * + * Test the string converters in libCom/cvtFast/cvtFast.c + * + * To Do: Test Char/Uchar/Short/Ushort/Long/Ulong versions + */ + +#include +#include + +#include "epicsUnitTest.h" +#include "cvtFast.h" +#include "epicsStdlib.h" +#include "testMain.h" + +#define tryIString(typ, lit, siz) \ + len = cvt##typ##ToString(lit, buf); \ + if (!testOk(len == siz, "cvt"#typ"ToString(" #lit ") == " #siz)) \ + testDiag("length returned was %u", (unsigned) len); \ + status = epicsParse##typ(buf, &val_##typ, 10, NULL); \ + testOk(!status, "epicsParse"#typ"('%s') OK", buf); \ + testOk(val_##typ == lit, #lit " => '%s'", buf); + +#define tryFString(typ, lit, prec, siz) \ + len = cvt##typ##ToString(lit, buf, prec); \ + if (!testOk(len == siz, "cvt"#typ"ToString(" #lit ", %d) == " #siz, prec)) \ + testDiag("length returned was %u", (unsigned) len); \ + status = epicsParse##typ(buf, &val_##typ, NULL); \ + testOk(!status, "epicsParse"#typ"('%s') OK", buf); \ + testOk(fabs(val_##typ - lit) < 0.5 * pow(10, -prec), #lit " => '%s'", buf); + + +MAIN(cvtFastTest) +{ + char buf[80]; + size_t len; + long status; + epicsUInt32 val_UInt32; + epicsInt32 val_Int32; + epicsUInt64 val_UInt64; + epicsInt64 val_Int64; + epicsFloat32 val_Float; + epicsFloat64 val_Double; + +#if defined(WIN32) && (!defined(_MINGW) || __MSVCRT_VERSION__ >= 0x0800) + _set_output_format(_TWO_DIGIT_EXPONENT); +#endif + + testPlan(1062); + + /* Arguments: type, value, num chars */ + testDiag("------------------------------------------------------"); + testDiag("** Positive Int32 **"); + tryIString(Int32, 0, 1); + tryIString(Int32, 1, 1); + tryIString(Int32, 10, 2); + tryIString(Int32, 100, 3); + tryIString(Int32, 254, 3); + tryIString(Int32, 255, 3); + tryIString(Int32, 256, 3); + tryIString(Int32, 257, 3); + tryIString(Int32, 1000, 4); + tryIString(Int32, 10000, 5); + tryIString(Int32, 32766, 5); + tryIString(Int32, 32767, 5); + tryIString(Int32, 32768, 5); + tryIString(Int32, 32769, 5); + tryIString(Int32, 65534, 5); + tryIString(Int32, 65535, 5); + tryIString(Int32, 65536, 5); + tryIString(Int32, 65537, 5); + tryIString(Int32, 2147483646, 10); + tryIString(Int32, 2147483647, 10); + + testDiag("------------------------------------------------------"); + testDiag("** Negative Int32 **"); + tryIString(Int32, -1, 2); + tryIString(Int32, -10, 3); + tryIString(Int32, -100, 4); + tryIString(Int32, -254, 4); + tryIString(Int32, -255, 4); + tryIString(Int32, -256, 4); + tryIString(Int32, -257, 4); + tryIString(Int32, -1000, 5); + tryIString(Int32, -10000, 6); + tryIString(Int32, -32766, 6); + tryIString(Int32, -32767, 6); + tryIString(Int32, -32768, 6); + tryIString(Int32, -32769, 6); + tryIString(Int32, -65534, 6); + tryIString(Int32, -65535, 6); + tryIString(Int32, -65536, 6); + tryIString(Int32, -65537, 6); + tryIString(Int32, -2147483647, 11); + tryIString(Int32, -2147483648LL, 11); + + testDiag("------------------------------------------------------"); + testDiag("** UInt32 **"); + tryIString(UInt32, 0, 1); + tryIString(UInt32, 1, 1); + tryIString(UInt32, 10, 2); + tryIString(UInt32, 100, 3); + tryIString(UInt32, 254, 3); + tryIString(UInt32, 255, 3); + tryIString(UInt32, 256, 3); + tryIString(UInt32, 257, 3); + tryIString(UInt32, 1000, 4); + tryIString(UInt32, 10000, 5); + tryIString(UInt32, 32766, 5); + tryIString(UInt32, 32767, 5); + tryIString(UInt32, 32768, 5); + tryIString(UInt32, 32769, 5); + tryIString(UInt32, 65534, 5); + tryIString(UInt32, 65535, 5); + tryIString(UInt32, 65536, 5); + tryIString(UInt32, 65537, 5); + tryIString(UInt32, 2147483646ULL, 10); + tryIString(UInt32, 2147483647ULL, 10); + tryIString(UInt32, 2147483648ULL, 10); + tryIString(UInt32, 4294967294ULL, 10); + tryIString(UInt32, 4294967295ULL, 10); + + testDiag("------------------------------------------------------"); + testDiag("** Positive Int64 **"); + tryIString(Int64, 0, 1); + tryIString(Int64, 1, 1); + tryIString(Int64, 10, 2); + tryIString(Int64, 100, 3); + tryIString(Int64, 254, 3); + tryIString(Int64, 255, 3); + tryIString(Int64, 256, 3); + tryIString(Int64, 257, 3); + tryIString(Int64, 1000, 4); + tryIString(Int64, 10000, 5); + tryIString(Int64, 32766, 5); + tryIString(Int64, 32767, 5); + tryIString(Int64, 32768, 5); + tryIString(Int64, 32769, 5); + tryIString(Int64, 65534, 5); + tryIString(Int64, 65535, 5); + tryIString(Int64, 65536, 5); + tryIString(Int64, 65537, 5); + tryIString(Int64, 2147483646, 10); + tryIString(Int64, 2147483647, 10); + tryIString(Int64, 2147483648LL, 10); + tryIString(Int64, 9223372036854775806LL, 19); + tryIString(Int64, 9223372036854775807LL, 19); + + testDiag("------------------------------------------------------"); + testDiag("** Negative Int64 **"); + tryIString(Int64, -1, 2); + tryIString(Int64, -10, 3); + tryIString(Int64, -100, 4); + tryIString(Int64, -254, 4); + tryIString(Int64, -255, 4); + tryIString(Int64, -256, 4); + tryIString(Int64, -257, 4); + tryIString(Int64, -1000, 5); + tryIString(Int64, -10000, 6); + tryIString(Int64, -32766, 6); + tryIString(Int64, -32767, 6); + tryIString(Int64, -32768, 6); + tryIString(Int64, -32769, 6); + tryIString(Int64, -65534, 6); + tryIString(Int64, -65535, 6); + tryIString(Int64, -65536, 6); + tryIString(Int64, -65537, 6); + tryIString(Int64, -2147483647, 11); + tryIString(Int64, -2147483648LL, 11); + tryIString(Int64, -2147483649LL, 11); + tryIString(Int64, -9223372036854775806LL, 20); + tryIString(Int64, -9223372036854775807LL, 20); + tryIString(Int64, -9223372036854775807LL-1, 20); + + testDiag("------------------------------------------------------"); + testDiag("** UInt64 **"); + tryIString(UInt64, 0, 1); + tryIString(UInt64, 1, 1); + tryIString(UInt64, 10, 2); + tryIString(UInt64, 100, 3); + tryIString(UInt64, 254, 3); + tryIString(UInt64, 255, 3); + tryIString(UInt64, 256, 3); + tryIString(UInt64, 257, 3); + tryIString(UInt64, 1000, 4); + tryIString(UInt64, 10000, 5); + tryIString(UInt64, 32766, 5); + tryIString(UInt64, 32767, 5); + tryIString(UInt64, 32768, 5); + tryIString(UInt64, 32769, 5); + tryIString(UInt64, 65534, 5); + tryIString(UInt64, 65535, 5); + tryIString(UInt64, 65536, 5); + tryIString(UInt64, 65537, 5); + tryIString(UInt64, 2147483646, 10); + tryIString(UInt64, 2147483647, 10); + tryIString(UInt64, 2147483648U, 10); + tryIString(UInt64, 2147483649U, 10); + tryIString(UInt64, 4294967294U, 10); + tryIString(UInt64, 4294967295U, 10); + tryIString(UInt64, 4294967296ULL, 10); + tryIString(UInt64, 4294967297ULL, 10); + tryIString(UInt64, 9223372036854775806ULL, 19); + tryIString(UInt64, 9223372036854775807ULL, 19); + tryIString(UInt64, 9223372036854775808ULL, 19); + tryIString(UInt64, 18446744073709551614ULL, 20); + tryIString(UInt64, 18446744073709551615ULL, 20); + + /* Arguments: type, value, precision, num chars */ + testDiag("------------------------------------------------------"); + testDiag("** Positive Float fixed-point **"); + tryFString(Float, 0, 0, 1); + tryFString(Float, 0, 1, 3); + tryFString(Float, 0, 2, 4); + tryFString(Float, 0, 3, 5); + tryFString(Float, 0, 4, 6); + tryFString(Float, 0, 5, 7); + tryFString(Float, 0, 6, 8); + tryFString(Float, 0, 7, 9); + tryFString(Float, 0, 8, 10); + tryFString(Float, FLT_MIN, 0, 1); + tryFString(Float, FLT_MIN, 1, 3); + tryFString(Float, FLT_MIN, 2, 4); + tryFString(Float, FLT_MIN, 3, 5); + tryFString(Float, FLT_MIN, 4, 6); + tryFString(Float, FLT_MIN, 5, 7); + tryFString(Float, FLT_MIN, 6, 8); + tryFString(Float, FLT_MIN, 7, 9); + tryFString(Float, FLT_MIN, 8, 10); + tryFString(Float, 0.000000004999999, 8, 10); + tryFString(Float, 0.000000005000001, 8, 10); + tryFString(Float, 0.00000004999999, 7, 9); + tryFString(Float, 0.00000005000001, 7, 9); + tryFString(Float, 0.0000004999999, 6, 8); + tryFString(Float, 0.0000005000001, 6, 8); + tryFString(Float, 0.000004999999, 5, 7); + tryFString(Float, 0.000005000001, 5, 7); + tryFString(Float, 0.00004999999, 4, 6); + tryFString(Float, 0.00005000001, 4, 6); + tryFString(Float, 0.0004999999, 3, 5); + tryFString(Float, 0.0005000001, 3, 5); + tryFString(Float, 0.004999999, 2, 4); + tryFString(Float, 0.005000001, 2, 4); + tryFString(Float, 0.04999999, 1, 3); + tryFString(Float, 0.05000001, 1, 3); + tryFString(Float, 0.4999999, 0, 1); + tryFString(Float, 0.5000001, 0, 1); + tryFString(Float, 1, 0, 1); + tryFString(Float, 1, 1, 3); + tryFString(Float, 1, 2, 4); + tryFString(Float, 1, 3, 5); + tryFString(Float, 1, 4, 6); + tryFString(Float, 1, 5, 7); + tryFString(Float, 1, 6, 8); + tryFString(Float, 1, 7, 9); + tryFString(Float, 1, 8, 10); + tryFString(Float, 1.0500001, 1, 3); + tryFString(Float, 1.1, 1, 3); + tryFString(Float, 1.1499999, 1, 3); + tryFString(Float, 9.5000001, 0, 2); + tryFString(Float, 10, 0, 2); + tryFString(Float, 10, 1, 4); + tryFString(Float, 10, 8, 11); + tryFString(Float, 100, 0, 3); + tryFString(Float, 100, 1, 5); + tryFString(Float, 100, 8, 12); + tryFString(Float, 1000, 0, 4); + tryFString(Float, 1000, 1, 6); + tryFString(Float, 1000, 8, 13); + tryFString(Float, 10000, 0, 5); + tryFString(Float, 10000, 1, 7); + tryFString(Float, 10000, 8, 14); + tryFString(Float, 100000, 0, 6); + tryFString(Float, 100000, 1, 8); + tryFString(Float, 100000, 8, 15); + tryFString(Float, 1000000, 0, 7); + tryFString(Float, 1000000, 1, 9); + tryFString(Float, 1000000, 8, 16); + tryFString(Float, 10000000, 0, 8); + tryFString(Float, 10000000, 1, 10); + tryFString(Float, 10000000, 8, 17); + + testDiag("------------------------------------------------------"); + testDiag("** Negative Float fixed-point **"); + tryFString(Float, -FLT_MIN, 0, 2); + tryFString(Float, -FLT_MIN, 1, 4); + tryFString(Float, -FLT_MIN, 8, 11); + tryFString(Float, -1, 0, 2); + tryFString(Float, -1, 1, 4); + tryFString(Float, -1, 8, 11); + tryFString(Float, -1.0500001, 1, 4); + tryFString(Float, -1.1, 1, 4); + tryFString(Float, -1.1499999, 1, 4); + tryFString(Float, -9.5000001, 0, 3); + tryFString(Float, -10, 0, 3); + tryFString(Float, -10, 1, 5); + tryFString(Float, -10, 8, 12); + tryFString(Float, -100, 0, 4); + tryFString(Float, -100, 1, 6); + tryFString(Float, -100, 8, 13); + tryFString(Float, -1000, 0, 5); + tryFString(Float, -1000, 1, 7); + tryFString(Float, -1000, 8, 14); + tryFString(Float, -10000, 0, 6); + tryFString(Float, -10000, 1, 8); + tryFString(Float, -10000, 8, 15); + tryFString(Float, -100000, 0, 7); + tryFString(Float, -100000, 1, 9); + tryFString(Float, -100000, 8, 16); + tryFString(Float, -1000000, 0, 8); + tryFString(Float, -1000000, 1, 10); + tryFString(Float, -1000000, 8, 17); + tryFString(Float, -10000000, 0, 9); + tryFString(Float, -10000000, 1, 11); + tryFString(Float, -10000000, 8, 18); + + /* + * Values > 1e7 trigger the %e format. + */ + testDiag("------------------------------------------------------"); + testDiag("** Positive Float scientific **"); + tryFString(Float, 1e+08, 0, 6); + tryFString(Float, 1e+08, 1, 8); + tryFString(Float, 1e+08, 2, 9); + tryFString(Float, 1e+08, 3, 10); + tryFString(Float, 1e+08, 4, 11); + tryFString(Float, 1e+08, 5, 12); + tryFString(Float, 1e+08, 6, 13); + + testDiag("------------------------------------------------------"); + testDiag("** Positive Double fixed-point **"); + tryFString(Double, 0, 0, 1); + tryFString(Double, 0, 1, 3); + tryFString(Double, 0, 2, 4); + tryFString(Double, 0, 3, 5); + tryFString(Double, 0, 4, 6); + tryFString(Double, 0, 5, 7); + tryFString(Double, 0, 6, 8); + tryFString(Double, 0, 7, 9); + tryFString(Double, 0, 8, 10); + tryFString(Double, DBL_MIN, 0, 1); + tryFString(Double, DBL_MIN, 1, 3); + tryFString(Double, DBL_MIN, 2, 4); + tryFString(Double, DBL_MIN, 3, 5); + tryFString(Double, DBL_MIN, 4, 6); + tryFString(Double, DBL_MIN, 5, 7); + tryFString(Double, DBL_MIN, 6, 8); + tryFString(Double, DBL_MIN, 7, 9); + tryFString(Double, DBL_MIN, 8, 10); + tryFString(Double, 0.000000004999999, 8, 10); + tryFString(Double, 0.000000005000001, 8, 10); + tryFString(Double, 0.00000004999999, 7, 9); + tryFString(Double, 0.00000005000001, 7, 9); + tryFString(Double, 0.0000004999999, 6, 8); + tryFString(Double, 0.0000005000001, 6, 8); + tryFString(Double, 0.000004999999, 5, 7); + tryFString(Double, 0.000005000001, 5, 7); + tryFString(Double, 0.00004999999, 4, 6); + tryFString(Double, 0.00005000001, 4, 6); + tryFString(Double, 0.0004999999, 3, 5); + tryFString(Double, 0.0005000001, 3, 5); + tryFString(Double, 0.004999999, 2, 4); + tryFString(Double, 0.005000001, 2, 4); + tryFString(Double, 0.04999999, 1, 3); + tryFString(Double, 0.05000001, 1, 3); + tryFString(Double, 0.4999999, 0, 1); + tryFString(Double, 0.5000001, 0, 1); + tryFString(Double, 1, 0, 1); + tryFString(Double, 1, 1, 3); + tryFString(Double, 1, 2, 4); + tryFString(Double, 1, 3, 5); + tryFString(Double, 1, 4, 6); + tryFString(Double, 1, 5, 7); + tryFString(Double, 1, 6, 8); + tryFString(Double, 1, 7, 9); + tryFString(Double, 1, 8, 10); + tryFString(Double, 1.0500001, 1, 3); + tryFString(Double, 1.1, 1, 3); + tryFString(Double, 1.1499999, 1, 3); + tryFString(Double, 9.5000001, 0, 2); + tryFString(Double, 10, 0, 2); + tryFString(Double, 10, 1, 4); + tryFString(Double, 10, 8, 11); + tryFString(Double, 100, 0, 3); + tryFString(Double, 100, 1, 5); + tryFString(Double, 100, 8, 12); + tryFString(Double, 1000, 0, 4); + tryFString(Double, 1000, 1, 6); + tryFString(Double, 1000, 8, 13); + tryFString(Double, 10000, 0, 5); + tryFString(Double, 10000, 1, 7); + tryFString(Double, 10000, 8, 14); + tryFString(Double, 100000, 0, 6); + tryFString(Double, 100000, 1, 8); + tryFString(Double, 100000, 8, 15); + tryFString(Double, 1000000, 0, 7); + tryFString(Double, 1000000, 1, 9); + tryFString(Double, 1000000, 8, 16); + tryFString(Double, 10000000, 0, 8); + tryFString(Double, 10000000, 1, 10); + tryFString(Double, 10000000, 8, 17); + + testDiag("------------------------------------------------------"); + testDiag("** Negative Double fixed-point **"); + tryFString(Double, -DBL_MIN, 0, 2); + tryFString(Double, -DBL_MIN, 1, 4); + tryFString(Double, -DBL_MIN, 8, 11); + tryFString(Double, -1, 0, 2); + tryFString(Double, -1, 1, 4); + tryFString(Double, -1, 8, 11); + tryFString(Double, -1.0500001, 1, 4); + tryFString(Double, -1.1, 1, 4); + tryFString(Double, -1.1499999, 1, 4); + tryFString(Double, -9.5000001, 0, 3); + tryFString(Double, -10, 0, 3); + tryFString(Double, -10, 1, 5); + tryFString(Double, -10, 8, 12); + tryFString(Double, -100, 0, 4); + tryFString(Double, -100, 1, 6); + tryFString(Double, -100, 8, 13); + tryFString(Double, -1000, 0, 5); + tryFString(Double, -1000, 1, 7); + tryFString(Double, -1000, 8, 14); + tryFString(Double, -10000, 0, 6); + tryFString(Double, -10000, 1, 8); + tryFString(Double, -10000, 8, 15); + tryFString(Double, -100000, 0, 7); + tryFString(Double, -100000, 1, 9); + tryFString(Double, -100000, 8, 16); + tryFString(Double, -1000000, 0, 8); + tryFString(Double, -1000000, 1, 10); + tryFString(Double, -1000000, 8, 17); + tryFString(Double, -10000000, 0, 9); + tryFString(Double, -10000000, 1, 11); + tryFString(Double, -10000000, 8, 18); + + /* + * Values > 1e7 trigger the %e format. + * Windows may print 3 digit exponents... + */ + testDiag("------------------------------------------------------"); + testDiag("** Positive Double scientific **"); + tryFString(Double, 1e+17, 0, 7); + tryFString(Double, 1e+17, 1, 8); + tryFString(Double, 1e+17, 2, 9); + tryFString(Double, 1e+17, 3, 10); + tryFString(Double, 1e+17, 4, 11); + tryFString(Double, 1e+17, 5, 12); + + return testDone(); +} diff --git a/src/tools/DBD/Recfield.pm b/src/tools/DBD/Recfield.pm index 73a98123c..89beb7be7 100644 --- a/src/tools/DBD/Recfield.pm +++ b/src/tools/DBD/Recfield.pm @@ -12,6 +12,8 @@ our %field_types = ( DBF_USHORT => $RXuintx, DBF_LONG => $RXintx, DBF_ULONG => $RXuintx, + DBF_INT64 => $RXintx, + DBF_UINT64 => $RXuintx, DBF_FLOAT => $RXnum, DBF_DOUBLE => $RXnum, DBF_ENUM => qr/.*/, @@ -317,6 +319,43 @@ sub toDeclaration { } +################################################################################ + +package DBD::Recfield::DBF_INT64; + +use DBD::Base; +@ISA = qw(DBD::Recfield); + +sub legal_value { + my ($this, $value) = @_; + $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe; + return ($value =~ m/^ $RXint $/x); +} + +sub toDeclaration { + return shift->SUPER::toDeclaration("epicsInt64"); +} + + +################################################################################ + +package DBD::Recfield::DBF_UINT64; + +use DBD::Base; +@ISA = qw(DBD::Recfield); + +sub legal_value { + my ($this, $value) = @_; + $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe; + return ($value =~ m/^ $RXuint $/x and + $value >= 0); +} + +sub toDeclaration { + return shift->SUPER::toDeclaration("epicsUInt64"); +} + + ################################################################################ package DBD::Recfield::DBF_FLOAT; From 2d4243981f0c012577a4c5200f7c0ebc1fdb966c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 12 Jul 2014 01:12:08 -0500 Subject: [PATCH 02/25] Fix warnings found by clang --- src/ioc/db/dbTest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ioc/db/dbTest.c b/src/ioc/db/dbTest.c index d5d5d0cc6..e707dab7f 100644 --- a/src/ioc/db/dbTest.c +++ b/src/ioc/db/dbTest.c @@ -958,7 +958,7 @@ static void printBuffer( case DBR_SHORT: for (i = 0; i < no_elements; i++) { - epicsInt32 val = *(epicsInt16 *) pbuffer; + epicsInt16 val = *(epicsInt16 *) pbuffer; sprintf(pmsg, "%hd = 0x%hx", val, val); dbpr_msgOut(pMsgBuff, tab_size); @@ -968,7 +968,7 @@ static void printBuffer( case DBR_USHORT: for (i = 0; i < no_elements; i++) { - epicsUInt32 val = *(epicsUInt16 *) pbuffer; + epicsUInt16 val = *(epicsUInt16 *) pbuffer; sprintf(pmsg, "%hu = 0x%hx", val, val); dbpr_msgOut(pMsgBuff, tab_size); From 4a5a675ef850ec61bb06f177f24334cd986aa037 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 24 Aug 2014 23:48:32 -0500 Subject: [PATCH 03/25] Remove development printf() statements --- src/ioc/db/dbFastLinkConv.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ioc/db/dbFastLinkConv.c b/src/ioc/db/dbFastLinkConv.c index 27f21fb15..f98c4b365 100644 --- a/src/ioc/db/dbFastLinkConv.c +++ b/src/ioc/db/dbFastLinkConv.c @@ -201,7 +201,6 @@ static long cvt_st_q( const dbAddr *paddr) { char *end; -printf("cvt_st_q('%s')\n", from); if (*from == 0) { *to = 0; @@ -922,7 +921,6 @@ static long cvt_q_q( epicsInt64 *to, const dbAddr *paddr) { -printf("cvt_q_q(%lld)\n", *from); *to=*from; return(0); } @@ -932,7 +930,6 @@ static long cvt_q_uq( epicsUInt64 *to, const dbAddr *paddr) { -printf("cvt_q_qq(%lld)\n", *from); *to=*from; return(0); } From f97c1a345ecccc1922a032837d58f59b1ad25629 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 16 Mar 2016 09:44:35 -0500 Subject: [PATCH 04/25] Fix cvtFast and tests We might still want to change the actual behaviour though, see the FIXME comments. --- src/libCom/cvtFast/cvtFast.c | 11 ++- src/libCom/test/cvtFastPerform.cpp | 117 ++++++++++++++++++----------- src/libCom/test/cvtFastTest.c | 12 +-- 3 files changed, 90 insertions(+), 50 deletions(-) diff --git a/src/libCom/cvtFast/cvtFast.c b/src/libCom/cvtFast/cvtFast.c index 3fb6a3d05..4e04b4515 100644 --- a/src/libCom/cvtFast/cvtFast.c +++ b/src/libCom/cvtFast/cvtFast.c @@ -38,8 +38,15 @@ int cvtFloatToString(float flt_value, char *pdest, char *startAddr; /* can this routine handle this conversion */ - if (isnan(flt_value) || precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) { - sprintf(pdest,"%12.5e",(double)flt_value); + if (isnan(flt_value) || precision > 8 || + flt_value > 10000000.0 || flt_value < -10000000.0) { + if (precision > 8 || flt_value >= 1e8 || flt_value <= -1e8) { + if (precision > 12) precision = 12; /* FIXME */ + sprintf(pdest, "%*.*e", precision+6, precision, (double) flt_value); + } else { + if (precision > 3) precision = 3; /* FIXME */ + sprintf(pdest, "%.*f", precision, (double) flt_value); + } return((int)strlen(pdest)); } startAddr = pdest; diff --git a/src/libCom/test/cvtFastPerform.cpp b/src/libCom/test/cvtFastPerform.cpp index f8ae7c270..86bbcbd8a 100644 --- a/src/libCom/test/cvtFastPerform.cpp +++ b/src/libCom/test/cvtFastPerform.cpp @@ -22,30 +22,44 @@ public: void execute (); protected: char _pDst[128]; - double _srcVal; + double _srcDbl; + float _srcFlt; unsigned short _prec; static unsigned const _nUnrolled = 10; static const unsigned _uSecPerSec = 1000000; static unsigned const _nIterations = 10000; + virtual const char *_name(void) = 0; + virtual int _maxPrecision(void) = 0; virtual void _target () = 0; void _measure (); Test ( const Test & ); Test & operator = ( Test & ); }; -class TestCvtFastDouble : public Test { +class TestCvtFastFloat : public Test { protected: void _target (); + const char *_name (void) { return "cvtFloatToString"; } + int _maxPrecision(void) { return 12; } +}; + +class TestCvtFastDouble : public Test { +protected: + void _target (void); + const char *_name (void) { return "cvtDoubleToString"; } + int _maxPrecision(void) { return 17; } }; class TestSNPrintf : public Test { protected: void _target (); + const char *_name (void) { return "epicsSnprintf"; } + int _maxPrecision(void) { return 17; } }; Test :: Test () : - _srcVal ( 0.0 ), _prec ( 0 ) + _srcDbl ( 0.0 ), _prec ( 0 ) { } @@ -55,28 +69,31 @@ Test :: ~Test () void Test :: execute () { - static const unsigned lowPrecision = 2; - static const unsigned highPrecision = DBL_MANT_DIG; for ( unsigned i = 0; i < 3; i++ ) { double mVal = rand (); mVal /= (RAND_MAX + 1.0); - double fEVal = rand (); - fEVal /= (RAND_MAX + 1.0); - fEVal *= DBL_MAX_EXP - DBL_MIN_EXP; - fEVal += DBL_MIN_EXP; - int eVal = static_cast < int > ( fEVal + 0.5 ); - _srcVal = ldexp ( mVal, eVal ); - for ( _prec = lowPrecision; - _prec <= highPrecision; _prec += 4u ) { + double eVal = rand (); + eVal /= (RAND_MAX + 1.0); + double dVal = eVal; + dVal *= DBL_MAX_EXP - DBL_MIN_EXP; + dVal += DBL_MIN_EXP; + int dEVal = static_cast < int > ( dVal + 0.5 ); + float fVal = eVal; + fVal *= FLT_MAX_EXP - FLT_MIN_EXP; + fVal += FLT_MIN_EXP; + int fEVal = static_cast < int > ( fVal + 0.5 ); + _srcDbl = ldexp ( mVal, dEVal ); + _srcFlt = ldexpf ( mVal, fEVal ); + for ( _prec = 0; _prec <= _maxPrecision(); _prec++ ) { _measure (); } - _srcVal = rand (); - _srcVal /= (RAND_MAX + 1.0); - _srcVal *= 10.0; - _srcVal -= 5.0; - for ( _prec = lowPrecision; - _prec <= highPrecision; _prec += 4u ) { + _srcDbl = rand (); + _srcDbl /= (RAND_MAX + 1.0); + _srcDbl *= 10.0; + _srcDbl -= 5.0; + _srcFlt = (float) _srcDbl; + for ( _prec = 0; _prec <= _maxPrecision(); _prec++ ) { _measure (); } } @@ -91,56 +108,72 @@ void Test :: _measure () epicsTime end = epicsTime :: getCurrent (); double elapsed = end - beg; elapsed /= _nIterations * _nUnrolled; - elapsed *= _uSecPerSec; - printf ( " %4.4f usec, prec=%i, val=%4.4g, for %s\n", - elapsed, _prec, _srcVal, typeid ( *this ).name () ); + printf ( "%17s: %12.9f sec, prec=%2i, out=%s\n", + this->_name (), elapsed, _prec, _pDst ); } +void TestCvtFastFloat :: _target () +{ + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); + cvtFloatToString ( _srcFlt, _pDst, _prec ); +} + void TestCvtFastDouble :: _target () { - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); - cvtDoubleToString ( _srcVal, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); + cvtDoubleToString ( _srcDbl, _pDst, _prec ); } void TestSNPrintf :: _target () { epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcVal ); + static_cast < int > ( _prec ), _srcDbl ); } MAIN(cvtFastPerform) { + TestCvtFastFloat testCvtFastFloat; TestCvtFastDouble testCvtFastDouble; TestSNPrintf testSNPrintf; + testCvtFastFloat.execute (); testCvtFastDouble.execute (); testSNPrintf.execute (); diff --git a/src/libCom/test/cvtFastTest.c b/src/libCom/test/cvtFastTest.c index 48c14d02e..cb7eeaf8a 100644 --- a/src/libCom/test/cvtFastTest.c +++ b/src/libCom/test/cvtFastTest.c @@ -326,12 +326,12 @@ MAIN(cvtFastTest) testDiag("------------------------------------------------------"); testDiag("** Positive Float scientific **"); tryFString(Float, 1e+08, 0, 6); - tryFString(Float, 1e+08, 1, 8); - tryFString(Float, 1e+08, 2, 9); - tryFString(Float, 1e+08, 3, 10); - tryFString(Float, 1e+08, 4, 11); - tryFString(Float, 1e+08, 5, 12); - tryFString(Float, 1e+08, 6, 13); + tryFString(Float, 1e+08, 1, 7); + tryFString(Float, 1e+08, 2, 8); + tryFString(Float, 1e+08, 3, 9); + tryFString(Float, 1e+08, 4, 10); + tryFString(Float, 1e+08, 5, 11); + tryFString(Float, 1e+08, 6, 12); testDiag("------------------------------------------------------"); testDiag("** Positive Double fixed-point **"); From e7bba3973710ce8ad25ba32674428d5136685522 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 16 Mar 2016 13:14:49 -0500 Subject: [PATCH 05/25] Add int64 record types and device support, from long --- src/std/dev/Makefile | 4 + src/std/dev/devI64inSoft.c | 79 ++++++ src/std/dev/devI64inSoftCallback.c | 222 +++++++++++++++ src/std/dev/devI64outSoft.c | 58 ++++ src/std/dev/devI64outSoftCallback.c | 69 +++++ src/std/dev/devSoft.dbd | 4 + src/std/rec/Makefile | 2 + src/std/rec/int64inRecord.c | 416 ++++++++++++++++++++++++++++ src/std/rec/int64inRecord.dbd | 161 +++++++++++ src/std/rec/int64outRecord.c | 393 ++++++++++++++++++++++++++ src/std/rec/int64outRecord.dbd | 184 ++++++++++++ 11 files changed, 1592 insertions(+) create mode 100644 src/std/dev/devI64inSoft.c create mode 100644 src/std/dev/devI64inSoftCallback.c create mode 100644 src/std/dev/devI64outSoft.c create mode 100644 src/std/dev/devI64outSoftCallback.c create mode 100644 src/std/rec/int64inRecord.c create mode 100644 src/std/rec/int64inRecord.dbd create mode 100644 src/std/rec/int64outRecord.c create mode 100644 src/std/rec/int64outRecord.dbd diff --git a/src/std/dev/Makefile b/src/std/dev/Makefile index 8e4e242f9..ec3713bd6 100644 --- a/src/std/dev/Makefile +++ b/src/std/dev/Makefile @@ -28,6 +28,8 @@ dbRecStd_SRCS += devBoDbState.c dbRecStd_SRCS += devCalcoutSoft.c dbRecStd_SRCS += devEventSoft.c dbRecStd_SRCS += devHistogramSoft.c +dbRecStd_SRCS += devI64inSoft.c +dbRecStd_SRCS += devI64outSoft.c dbRecStd_SRCS += devLiSoft.c dbRecStd_SRCS += devLoSoft.c dbRecStd_SRCS += devLsiSoft.c @@ -49,6 +51,7 @@ dbRecStd_SRCS += devGeneralTime.c dbRecStd_SRCS += devAiSoftCallback.c dbRecStd_SRCS += devBiSoftCallback.c +dbRecStd_SRCS += devI64inSoftCallback.c dbRecStd_SRCS += devLiSoftCallback.c dbRecStd_SRCS += devMbbiDirectSoftCallback.c dbRecStd_SRCS += devMbbiSoftCallback.c @@ -57,6 +60,7 @@ dbRecStd_SRCS += devSiSoftCallback.c dbRecStd_SRCS += devAoSoftCallback.c dbRecStd_SRCS += devBoSoftCallback.c dbRecStd_SRCS += devCalcoutSoftCallback.c +dbRecStd_SRCS += devI64outSoftCallback.c dbRecStd_SRCS += devLoSoftCallback.c dbRecStd_SRCS += devLsoSoftCallback.c dbRecStd_SRCS += devMbboSoftCallback.c diff --git a/src/std/dev/devI64inSoft.c b/src/std/dev/devI64inSoft.c new file mode 100644 index 000000000..f4e6bce83 --- /dev/null +++ b/src/std/dev/devI64inSoft.c @@ -0,0 +1,79 @@ +/*************************************************************************\ +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* $Revision-Id$ + * + * Original Author: Janet Anderson + * Date: 09-23-91 + */ + +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "recGbl.h" +#include "devSup.h" +#include "int64inRecord.h" +#include "epicsExport.h" + +/* Create the dset for devI64inSoft */ +static long init_record(int64inRecord *prec); +static long read_int64in(int64inRecord *prec); + +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_int64in; +} devI64inSoft = { + 5, + NULL, + NULL, + init_record, + NULL, + read_int64in +}; +epicsExportAddress(dset, devI64inSoft); + +static long init_record(int64inRecord *prec) +{ + /* INP must be CONSTANT, PV_LINK, DB_LINK or CA_LINK*/ + switch (prec->inp.type) { + case CONSTANT: + if (recGblInitConstantLink(&prec->inp, DBF_INT64, &prec->val)) + prec->udf = FALSE; + break; + case PV_LINK: + case DB_LINK: + case CA_LINK: + break; + default: + recGblRecordError(S_db_badField, (void *)prec, + "devI64inSoft (init_record) Illegal INP field"); + return S_db_badField; + } + return 0; +} + +static long read_int64in(int64inRecord *prec) +{ + long status; + + status = dbGetLink(&prec->inp, DBR_INT64, &prec->val, 0, 0); + if (!status && + prec->tsel.type == CONSTANT && + prec->tse == epicsTimeEventDeviceTime) + dbGetTimeStamp(&prec->inp, &prec->time); + return status; +} diff --git a/src/std/dev/devI64inSoftCallback.c b/src/std/dev/devI64inSoftCallback.c new file mode 100644 index 000000000..8c9e77896 --- /dev/null +++ b/src/std/dev/devI64inSoftCallback.c @@ -0,0 +1,222 @@ +/*************************************************************************\ +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* devI64inSoftCallback.c */ +/* + * Authors: Marty Kraimer & Andrew Johnson + */ + +#include +#include + +#include "alarm.h" +#include "callback.h" +#include "cantProceed.h" +#include "dbCommon.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "dbChannel.h" +#include "dbNotify.h" +#include "epicsAssert.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "int64inRecord.h" +#include "epicsExport.h" + + +#define GET_OPTIONS (DBR_STATUS | DBR_TIME) + +typedef struct devPvt { + processNotify pn; + CALLBACK callback; + long options; + int status; + struct { + DBRstatus + DBRtime + epicsInt32 value; + } buffer; +} devPvt; + + +static void getCallback(processNotify *ppn, notifyGetType type) +{ + int64inRecord *prec = (int64inRecord *)ppn->usrPvt; + devPvt *pdevPvt = (devPvt *)prec->dpvt; + long no_elements = 1; + + if (ppn->status == notifyCanceled) { + printf("devI64inSoftCallback::getCallback notifyCanceled\n"); + return; + } + + assert(type == getFieldType); + pdevPvt->status = dbChannelGetField(ppn->chan, DBR_INT64, + &pdevPvt->buffer, &pdevPvt->options, &no_elements, 0); +} + +static void doneCallback(processNotify *ppn) +{ + int64inRecord *prec = (int64inRecord *)ppn->usrPvt; + devPvt *pdevPvt = (devPvt *)prec->dpvt; + + callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec); +} + +static long add_record(dbCommon *pcommon) +{ + int64inRecord *prec = (int64inRecord *)pcommon; + DBLINK *plink = &prec->inp; + dbChannel *chan; + devPvt *pdevPvt; + processNotify *ppn; + + if (plink->type == CONSTANT) return 0; + + if (plink->type != PV_LINK) { + long status = S_db_badField; + + recGblRecordError(status, (void *)prec, + "devI64inSoftCallback (add_record) Illegal INP field"); + return status; + } + + chan = dbChannelCreate(plink->value.pv_link.pvname); + if (!chan) { + long status = S_db_notFound; + + recGblRecordError(status, (void *)prec, + "devI64inSoftCallback (init_record) linked record not found"); + return status; + } + + pdevPvt = calloc(1, sizeof(*pdevPvt)); + if (!pdevPvt) { + long status = S_db_noMemory; + + recGblRecordError(status, (void *)prec, + "devI64inSoftCallback (add_record) out of memory, calloc() failed"); + return status; + } + ppn = &pdevPvt->pn; + + plink->type = PN_LINK; + plink->value.pv_link.pvlMask &= pvlOptMsMode; /* Severity flags only */ + + ppn->usrPvt = prec; + ppn->chan = chan; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; + ppn->requestType = processGetRequest; + + pdevPvt->options = GET_OPTIONS; + + prec->dpvt = pdevPvt; + return 0; +} + +static long del_record(dbCommon *pcommon) { + int64inRecord *prec = (int64inRecord *)pcommon; + DBLINK *plink = &prec->inp; + devPvt *pdevPvt = (devPvt *)prec->dpvt; + + if (plink->type == CONSTANT) return 0; + assert(plink->type == PN_LINK); + + dbNotifyCancel(&pdevPvt->pn); + dbChannelDelete(pdevPvt->pn.chan); + free(pdevPvt); + + plink->type = PV_LINK; + return 0; +} + +static struct dsxt dsxtSoftCallback = { + add_record, del_record +}; + +static long init(int pass) +{ + if (pass == 0) devExtend(&dsxtSoftCallback); + return 0; +} + +static long init_record(int64inRecord *prec) +{ + /* INP must be CONSTANT or PN_LINK */ + switch (prec->inp.type) { + case CONSTANT: + if (recGblInitConstantLink(&prec->inp, DBR_INT64, &prec->val)) + prec->udf = FALSE; + break; + case PN_LINK: + /* Handled by add_record */ + break; + default: + recGblRecordError(S_db_badField, (void *)prec, + "devI64inSoftCallback (init_record) Illegal INP field"); + prec->pact = TRUE; + return S_db_badField; + } + return 0; +} + +static long read_int64in(int64inRecord *prec) +{ + devPvt *pdevPvt = (devPvt *)prec->dpvt; + + if (!prec->dpvt) + return 0; + + if (!prec->pact) { + dbProcessNotify(&pdevPvt->pn); + prec->pact = TRUE; + return 0; + } + + if (pdevPvt->status) { + recGblSetSevr(prec, READ_ALARM, INVALID_ALARM); + return pdevPvt->status; + } + + prec->val = pdevPvt->buffer.value; + prec->udf = FALSE; + + switch (prec->inp.value.pv_link.pvlMask & pvlOptMsMode) { + case pvlOptNMS: + break; + case pvlOptMSI: + if (pdevPvt->buffer.severity < INVALID_ALARM) + break; + /* else fall through */ + case pvlOptMS: + recGblSetSevr(prec, LINK_ALARM, pdevPvt->buffer.severity); + break; + case pvlOptMSS: + recGblSetSevr(prec, pdevPvt->buffer.status, + pdevPvt->buffer.severity); + break; + } + + if (prec->tsel.type == CONSTANT && + prec->tse == epicsTimeEventDeviceTime) + prec->time = pdevPvt->buffer.time; + return 0; +} + +/* Create the dset for devI64inSoftCallback */ +struct { + dset common; + DEVSUPFUN read_int64in; +} devI64inSoftCallback = { + {5, NULL, init, init_record, NULL}, + read_int64in +}; +epicsExportAddress(dset, devI64inSoftCallback); diff --git a/src/std/dev/devI64outSoft.c b/src/std/dev/devI64outSoft.c new file mode 100644 index 000000000..95f6e266c --- /dev/null +++ b/src/std/dev/devI64outSoft.c @@ -0,0 +1,58 @@ +/*************************************************************************\ +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* $Revision-Id$ */ +/* + * Original Author: Janet Anderson + * Date: 09-23-91 +*/ + +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "int64outRecord.h" +#include "epicsExport.h" + +/* Create the dset for devI64outSoft */ +static long init_record(int64outRecord *prec); +static long write_int64out(int64outRecord *prec); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN write_int64out; +} devI64outSoft = { + 5, + NULL, + NULL, + init_record, + NULL, + write_int64out +}; +epicsExportAddress(dset, devI64outSoft); + +static long init_record(int64outRecord *prec) +{ + return 0; +} + +static long write_int64out(int64outRecord *prec) +{ + dbPutLink(&prec->out, DBR_INT64, &prec->val,1); + return 0; +} diff --git a/src/std/dev/devI64outSoftCallback.c b/src/std/dev/devI64outSoftCallback.c new file mode 100644 index 000000000..bfb283523 --- /dev/null +++ b/src/std/dev/devI64outSoftCallback.c @@ -0,0 +1,69 @@ +/*************************************************************************\ +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Original Author: Marty Kraimer + * Date: 04NOV2003 + */ + +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "int64outRecord.h" +#include "epicsExport.h" + +/* Create the dset for devI64outSoftCallback */ +static long write_int64out(int64outRecord *prec); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN write_int64out; +} devI64outSoftCallback = { + 5, + NULL, + NULL, + NULL, + NULL, + write_int64out +}; +epicsExportAddress(dset, devI64outSoftCallback); + +static long write_int64out(int64outRecord *prec) +{ + struct link *plink = &prec->out; + long status; + + if (prec->pact) + return 0; + + if (plink->type != CA_LINK) { + status = dbPutLink(plink, DBR_INT64, &prec->val, 1); + return status; + } + + status = dbCaPutLinkCallback(plink, DBR_INT64, &prec->val, 1, + dbCaCallbackProcess, plink); + if (status) { + recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM); + return status; + } + + prec->pact = TRUE; + return 0; +} diff --git a/src/std/dev/devSoft.dbd b/src/std/dev/devSoft.dbd index 1314bf540..2d7a64be3 100644 --- a/src/std/dev/devSoft.dbd +++ b/src/std/dev/devSoft.dbd @@ -9,6 +9,8 @@ device(bo,CONSTANT,devBoSoft,"Soft Channel") device(calcout,CONSTANT,devCalcoutSoft,"Soft Channel") device(event,CONSTANT,devEventSoft,"Soft Channel") device(histogram,CONSTANT,devHistogramSoft,"Soft Channel") +device(int64in,CONSTANT,devI64inSoft,"Soft Channel") +device(int64out,CONSTANT,devI64outSoft,"Soft Channel") device(longin,CONSTANT,devLiSoft,"Soft Channel") device(longout,CONSTANT,devLoSoft,"Soft Channel") device(lsi,CONSTANT,devLsiSoft,"Soft Channel") @@ -37,6 +39,8 @@ device(ao,CONSTANT,devAoSoftCallback,"Async Soft Channel") device(bi,CONSTANT,devBiSoftCallback,"Async Soft Channel") device(bo,CONSTANT,devBoSoftCallback,"Async Soft Channel") device(calcout,CONSTANT,devCalcoutSoftCallback,"Async Soft Channel") +device(int64in,CONSTANT,devI64inSoftCallback,"Async Soft Channel") +device(int64out,CONSTANT,devI64outSoftCallback,"Async Soft Channel") device(longin,CONSTANT,devLiSoftCallback,"Async Soft Channel") device(longout,CONSTANT,devLoSoftCallback,"Async Soft Channel") device(lso,CONSTANT,devLsoSoftCallback,"Async Soft Channel") diff --git a/src/std/rec/Makefile b/src/std/rec/Makefile index 7515d769c..561058620 100644 --- a/src/std/rec/Makefile +++ b/src/std/rec/Makefile @@ -25,6 +25,8 @@ stdRecords += dfanoutRecord stdRecords += eventRecord stdRecords += fanoutRecord stdRecords += histogramRecord +stdRecords += int64inRecord +stdRecords += int64outRecord stdRecords += longinRecord stdRecords += longoutRecord stdRecords += lsiRecord diff --git a/src/std/rec/int64inRecord.c b/src/std/rec/int64inRecord.c new file mode 100644 index 000000000..700798c66 --- /dev/null +++ b/src/std/rec/int64inRecord.c @@ -0,0 +1,416 @@ +/*************************************************************************\ +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* $Revision-Id$ */ + +/* int64inRecord.c - Record Support Routines for int64in records */ +/* + * Original Author: Janet Anderson + * Date: 9/23/91 + */ + +#include +#include +#include +#include +#include +#include + +#include "dbDefs.h" +#include "epicsPrint.h" +#include "alarm.h" +#include "dbAccess.h" +#include "dbEvent.h" +#include "dbFldTypes.h" +#include "devSup.h" +#include "errMdef.h" +#include "recSup.h" +#include "recGbl.h" +#include "menuYesNo.h" + +#define GEN_SIZE_OFFSET +#include "int64inRecord.h" +#undef GEN_SIZE_OFFSET +#include "epicsExport.h" + + /* Hysterisis for alarm filtering: 1-1/e */ +#define THRESHOLD 0.6321 +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +static long init_record(int64inRecord *, int); +static long process(int64inRecord *); +#define special NULL +#define get_value NULL +#define cvt_dbaddr NULL +#define get_array_info NULL +#define put_array_info NULL +static long get_units(DBADDR *, char *); +#define get_precision NULL +#define get_enum_str NULL +#define get_enum_strs NULL +#define put_enum_str NULL +static long get_graphic_double(DBADDR *, struct dbr_grDouble *); +static long get_control_double(DBADDR *, struct dbr_ctrlDouble *); +static long get_alarm_double(DBADDR *, struct dbr_alDouble *); + +rset int64inRSET={ + RSETNUMBER, + report, + initialize, + init_record, + process, + special, + get_value, + cvt_dbaddr, + get_array_info, + put_array_info, + get_units, + get_precision, + get_enum_str, + get_enum_strs, + put_enum_str, + get_graphic_double, + get_control_double, + get_alarm_double +}; +epicsExportAddress(rset,int64inRSET); + + +struct int64indset { /* int64in input dset */ + long number; + DEVSUPFUN dev_report; + DEVSUPFUN init; + DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/ + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_int64in; /*returns: (-1,0)=>(failure,success)*/ +}; +static void checkAlarms(int64inRecord *prec, epicsTimeStamp *timeLast); +static void monitor(int64inRecord *prec); +static long readValue(int64inRecord *prec); + + +static long init_record(int64inRecord *prec, int pass) +{ + struct int64indset *pdset; + long status; + + if (pass==0) return(0); + + /* int64in.siml must be a CONSTANT or a PV_LINK or a DB_LINK */ + if (prec->siml.type == CONSTANT) { + recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm); + } + + /* int64in.siol must be a CONSTANT or a PV_LINK or a DB_LINK */ + if (prec->siol.type == CONSTANT) { + recGblInitConstantLink(&prec->siol,DBF_LONG,&prec->sval); + } + + if(!(pdset = (struct int64indset *)(prec->dset))) { + recGblRecordError(S_dev_noDSET,(void *)prec,"int64in: init_record"); + return(S_dev_noDSET); + } + /* must have read_int64in function defined */ + if( (pdset->number < 5) || (pdset->read_int64in == NULL) ) { + recGblRecordError(S_dev_missingSup,(void *)prec,"int64in: init_record"); + return(S_dev_missingSup); + } + if( pdset->init_record ) { + if((status=(*pdset->init_record)(prec))) return(status); + } + prec->mlst = prec->val; + prec->alst = prec->val; + prec->lalm = prec->val; + return(0); +} + +static long process(int64inRecord *prec) +{ + struct int64indset *pdset = (struct int64indset *)(prec->dset); + long status; + unsigned char pact=prec->pact; + epicsTimeStamp timeLast; + + if( (pdset==NULL) || (pdset->read_int64in==NULL) ) { + prec->pact=TRUE; + recGblRecordError(S_dev_missingSup,(void *)prec,"read_int64in"); + return(S_dev_missingSup); + } + timeLast = prec->time; + + status=readValue(prec); /* read the new value */ + /* check if device support set pact */ + if ( !pact && prec->pact ) return(0); + prec->pact = TRUE; + + recGblGetTimeStamp(prec); + if (status==0) prec->udf = FALSE; + + /* check for alarms */ + checkAlarms(prec, &timeLast); + /* check event list */ + monitor(prec); + /* process the forward scan link record */ + recGblFwdLink(prec); + + prec->pact=FALSE; + return(status); +} + +#define indexof(field) int64inRecord##field + +static long get_units(DBADDR *paddr,char *units) +{ + int64inRecord *prec=(int64inRecord *)paddr->precord; + + if(paddr->pfldDes->field_type == DBF_LONG) { + strncpy(units,prec->egu,DB_UNITS_SIZE); + } + return(0); +} + + +static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) +{ + int64inRecord *prec=(int64inRecord *)paddr->precord; + + switch (dbGetFieldIndex(paddr)) { + case indexof(VAL): + case indexof(HIHI): + case indexof(HIGH): + case indexof(LOW): + case indexof(LOLO): + case indexof(LALM): + case indexof(ALST): + case indexof(MLST): + case indexof(SVAL): + pgd->upper_disp_limit = prec->hopr; + pgd->lower_disp_limit = prec->lopr; + break; + default: + recGblGetGraphicDouble(paddr,pgd); + } + return(0); +} + +static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) +{ + int64inRecord *prec=(int64inRecord *)paddr->precord; + + switch (dbGetFieldIndex(paddr)) { + case indexof(VAL): + case indexof(HIHI): + case indexof(HIGH): + case indexof(LOW): + case indexof(LOLO): + case indexof(LALM): + case indexof(ALST): + case indexof(MLST): + case indexof(SVAL): + pcd->upper_ctrl_limit = prec->hopr; + pcd->lower_ctrl_limit = prec->lopr; + break; + default: + recGblGetControlDouble(paddr,pcd); + } + return(0); +} + +static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad) +{ + int64inRecord *prec=(int64inRecord *)paddr->precord; + + if(dbGetFieldIndex(paddr) == indexof(VAL)){ + pad->upper_alarm_limit = prec->hihi; + pad->upper_warning_limit = prec->high; + pad->lower_warning_limit = prec->low; + pad->lower_alarm_limit = prec->lolo; + } else recGblGetAlarmDouble(paddr,pad); + return(0); +} + +static void checkAlarms(int64inRecord *prec, epicsTimeStamp *timeLast) +{ + enum { + range_Lolo = 1, + range_Low, + range_Normal, + range_High, + range_Hihi + } alarmRange; + static const epicsEnum16 range_stat[] = { + SOFT_ALARM, LOLO_ALARM, LOW_ALARM, + NO_ALARM, HIGH_ALARM, HIHI_ALARM + }; + + double aftc, afvl; + epicsInt64 val, hyst, lalm; + epicsInt64 alev; + epicsEnum16 asev; + + if (prec->udf) { + recGblSetSevr(prec, UDF_ALARM, prec->udfs); + prec->afvl = 0; + return; + } + + val = prec->val; + hyst = prec->hyst; + lalm = prec->lalm; + + /* check VAL against alarm limits */ + if ((asev = prec->hhsv) && + (val >= (alev = prec->hihi) || + ((lalm == alev) && (val >= alev - hyst)))) + alarmRange = range_Hihi; + else + if ((asev = prec->llsv) && + (val <= (alev = prec->lolo) || + ((lalm == alev) && (val <= alev + hyst)))) + alarmRange = range_Lolo; + else + if ((asev = prec->hsv) && + (val >= (alev = prec->high) || + ((lalm == alev) && (val >= alev - hyst)))) + alarmRange = range_High; + else + if ((asev = prec->lsv) && + (val <= (alev = prec->low) || + ((lalm == alev) && (val <= alev + hyst)))) + alarmRange = range_Low; + else { + alev = val; + asev = NO_ALARM; + alarmRange = range_Normal; + } + + aftc = prec->aftc; + afvl = 0; + + if (aftc > 0) { + /* Apply level filtering */ + afvl = prec->afvl; + if (afvl == 0) { + afvl = (double)alarmRange; + } else { + double t = epicsTimeDiffInSeconds(&prec->time, timeLast); + double alpha = aftc / (t + aftc); + + /* The sign of afvl indicates whether the result should be + * rounded up or down. This gives the filter hysteresis. + * If afvl > 0 the floor() function rounds to a lower alarm + * level, otherwise to a higher. + */ + afvl = alpha * afvl + + ((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange; + if (afvl - floor(afvl) > THRESHOLD) + afvl = -afvl; /* reverse rounding */ + + alarmRange = abs((int)floor(afvl)); + switch (alarmRange) { + case range_Hihi: + asev = prec->hhsv; + alev = prec->hihi; + break; + case range_High: + asev = prec->hsv; + alev = prec->high; + break; + case range_Normal: + asev = NO_ALARM; + break; + case range_Low: + asev = prec->lsv; + alev = prec->low; + break; + case range_Lolo: + asev = prec->llsv; + alev = prec->lolo; + break; + } + } + } + prec->afvl = afvl; + + if (asev) { + /* Report alarm condition, store LALM for future HYST calculations */ + if (recGblSetSevr(prec, range_stat[alarmRange], asev)) + prec->lalm = alev; + } else { + /* No alarm condition, reset LALM */ + prec->lalm = val; + } +} + +/* DELTA calculates the absolute difference between its arguments + * expressed as an unsigned 32-bit integer */ +#define DELTA(last, val) \ + ((epicsUInt32) ((last) > (val) ? (last) - (val) : (val) - (last))) + +static void monitor(int64inRecord *prec) +{ + unsigned short monitor_mask = recGblResetAlarms(prec); + + if (prec->mdel < 0 || + DELTA(prec->mlst, prec->val) > (epicsUInt32) prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } + + if (prec->adel < 0 || + DELTA(prec->alst, prec->val) > (epicsUInt32) prec->adel) { + /* post events for archive value change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; + } + + /* send out monitors connected to the value field */ + if (monitor_mask) + db_post_events(prec, &prec->val, monitor_mask); +} + +static long readValue(int64inRecord *prec) +{ + long status; + struct int64indset *pdset = (struct int64indset *) (prec->dset); + + if (prec->pact == TRUE){ + status=(*pdset->read_int64in)(prec); + return(status); + } + + status=dbGetLink(&(prec->siml),DBR_USHORT, &(prec->simm),0,0); + if (status) + return(status); + + if (prec->simm == menuYesNoNO){ + status=(*pdset->read_int64in)(prec); + return(status); + } + if (prec->simm == menuYesNoYES){ + status=dbGetLink(&(prec->siol),DBR_LONG, + &(prec->sval),0,0); + + if (status==0) { + prec->val=prec->sval; + prec->udf=FALSE; + } + } else { + status=-1; + recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM); + return(status); + } + recGblSetSevr(prec,SIMM_ALARM,prec->sims); + + return(status); +} diff --git a/src/std/rec/int64inRecord.dbd b/src/std/rec/int64inRecord.dbd new file mode 100644 index 000000000..b603c709e --- /dev/null +++ b/src/std/rec/int64inRecord.dbd @@ -0,0 +1,161 @@ +#************************************************************************* +# Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* +recordtype(int64in) { + include "dbCommon.dbd" + field(VAL,DBF_INT64) { + prompt("Current value") + promptgroup(GUI_INPUTS) + asl(ASL0) + pp(TRUE) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup(GUI_INPUTS) + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Units name") + promptgroup(GUI_DISPLAY) + interest(1) + size(16) + prop(YES) + } + field(HOPR,DBF_INT64) { + prompt("High Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(LOPR,DBF_INT64) { + prompt("Low Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(HIHI,DBF_INT64) { + prompt("Hihi Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_INT64) { + prompt("Lolo Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_INT64) { + prompt("High Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_INT64) { + prompt("Low Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_INT64) { + prompt("Alarm Deadband") + promptgroup(GUI_ALARMS) + interest(1) + } + field(AFTC, DBF_DOUBLE) { + prompt("Alarm Filter Time Constant") + promptgroup(GUI_ALARMS) + interest(1) + } + field(AFVL, DBF_DOUBLE) { + prompt("Alarm Filter Value") + special(SPC_NOMOD) + interest(3) + } + field(ADEL,DBF_INT64) { + prompt("Archive Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(MDEL,DBF_INT64) { + prompt("Monitor Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(LALM,DBF_INT64) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_INT64) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_INT64) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + field(SIOL,DBF_INLINK) { + prompt("Sim Input Specifctn") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SVAL,DBF_INT64) { + prompt("Simulation Value") + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup(GUI_INPUTS) + interest(2) + menu(menuAlarmSevr) + } +} diff --git a/src/std/rec/int64outRecord.c b/src/std/rec/int64outRecord.c new file mode 100644 index 000000000..2c44c39c4 --- /dev/null +++ b/src/std/rec/int64outRecord.c @@ -0,0 +1,393 @@ +/*************************************************************************\ +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* $Revision-Id$ */ +/* + * Original Author: Janet Anderson + * Date: 9/23/91 + */ +#include +#include +#include +#include +#include + +#include "dbDefs.h" +#include "epicsPrint.h" +#include "alarm.h" +#include "dbAccess.h" +#include "dbEvent.h" +#include "dbFldTypes.h" +#include "devSup.h" +#include "errMdef.h" +#include "recSup.h" +#include "recGbl.h" +#include "menuYesNo.h" +#include "menuIvoa.h" +#include "menuOmsl.h" + +#define GEN_SIZE_OFFSET +#include "int64outRecord.h" +#undef GEN_SIZE_OFFSET +#include "epicsExport.h" + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +static long init_record(int64outRecord *, int); +static long process(int64outRecord *); +#define special NULL +#define get_value NULL +#define cvt_dbaddr NULL +#define get_array_info NULL +#define put_array_info NULL +static long get_units(DBADDR *, char *); +#define get_precision NULL +#define get_enum_str NULL +#define get_enum_strs NULL +#define put_enum_str NULL +static long get_graphic_double(DBADDR *, struct dbr_grDouble *); +static long get_control_double(DBADDR *, struct dbr_ctrlDouble *); +static long get_alarm_double(DBADDR *, struct dbr_alDouble *); + +rset int64outRSET={ + RSETNUMBER, + report, + initialize, + init_record, + process, + special, + get_value, + cvt_dbaddr, + get_array_info, + put_array_info, + get_units, + get_precision, + get_enum_str, + get_enum_strs, + put_enum_str, + get_graphic_double, + get_control_double, + get_alarm_double +}; +epicsExportAddress(rset,int64outRSET); + + +struct int64outdset { /* int64out input dset */ + long number; + DEVSUPFUN dev_report; + DEVSUPFUN init; + DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/ + DEVSUPFUN get_ioint_info; + DEVSUPFUN write_int64out;/*(-1,0)=>(failure,success*/ +}; +static void checkAlarms(int64outRecord *prec); +static void monitor(int64outRecord *prec); +static long writeValue(int64outRecord *prec); +static void convert(int64outRecord *prec, epicsInt64 value); + + +static long init_record(int64outRecord *prec, int pass) +{ + struct int64outdset *pdset; + long status=0; + + if (pass==0) return(0); + if (prec->siml.type == CONSTANT) { + recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm); + } + if(!(pdset = (struct int64outdset *)(prec->dset))) { + recGblRecordError(S_dev_noDSET,(void *)prec,"int64out: init_record"); + return(S_dev_noDSET); + } + /* must have write_int64out functions defined */ + if( (pdset->number < 5) || (pdset->write_int64out == NULL) ) { + recGblRecordError(S_dev_missingSup,(void *)prec,"int64out: init_record"); + return(S_dev_missingSup); + } + if (prec->dol.type == CONSTANT) { + if(recGblInitConstantLink(&prec->dol,DBF_INT64,&prec->val)) + prec->udf=FALSE; + } + if( pdset->init_record ) { + if((status=(*pdset->init_record)(prec))) return(status); + } + prec->mlst = prec->val; + prec->alst = prec->val; + prec->lalm = prec->val; + return(0); +} + +static long process(int64outRecord *prec) +{ + struct int64outdset *pdset = (struct int64outdset *)(prec->dset); + long status=0; + epicsInt64 value; + unsigned char pact=prec->pact; + + if( (pdset==NULL) || (pdset->write_int64out==NULL) ) { + prec->pact=TRUE; + recGblRecordError(S_dev_missingSup,(void *)prec,"write_int64out"); + return(S_dev_missingSup); + } + if (!prec->pact) { + if((prec->dol.type != CONSTANT) + && (prec->omsl == menuOmslclosed_loop)) { + status = dbGetLink(&(prec->dol),DBR_INT64, + &value,0,0); + if (prec->dol.type!=CONSTANT && RTN_SUCCESS(status)) + prec->udf=FALSE; + } + else { + value = prec->val; + } + if (!status) convert(prec,value); + } + + /* check for alarms */ + checkAlarms(prec); + + if (prec->nsev < INVALID_ALARM ) + status=writeValue(prec); /* write the new value */ + else { + switch (prec->ivoa) { + case (menuIvoaContinue_normally) : + status=writeValue(prec); /* write the new value */ + break; + case (menuIvoaDon_t_drive_outputs) : + break; + case (menuIvoaSet_output_to_IVOV) : + if(prec->pact == FALSE){ + prec->val=prec->ivov; + } + status=writeValue(prec); /* write the new value */ + break; + default : + status=-1; + recGblRecordError(S_db_badField,(void *)prec, + "int64out:process Illegal IVOA field"); + } + } + + /* check if device support set pact */ + if ( !pact && prec->pact ) return(0); + prec->pact = TRUE; + + recGblGetTimeStamp(prec); + + /* check event list */ + monitor(prec); + + /* process the forward scan link record */ + recGblFwdLink(prec); + + prec->pact=FALSE; + return(status); +} + +#define indexof(field) int64outRecord##field + +static long get_units(DBADDR *paddr,char *units) +{ + int64outRecord *prec=(int64outRecord *)paddr->precord; + + if(paddr->pfldDes->field_type == DBF_INT64) { + strncpy(units,prec->egu,DB_UNITS_SIZE); + } + return(0); +} + +static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd) +{ + int64outRecord *prec=(int64outRecord *)paddr->precord; + + switch (dbGetFieldIndex(paddr)) { + case indexof(VAL): + case indexof(HIHI): + case indexof(HIGH): + case indexof(LOW): + case indexof(LOLO): + case indexof(LALM): + case indexof(ALST): + case indexof(MLST): + pgd->upper_disp_limit = prec->hopr; + pgd->lower_disp_limit = prec->lopr; + break; + default: + recGblGetGraphicDouble(paddr,pgd); + } + return(0); +} + +static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd) +{ + int64outRecord *prec=(int64outRecord *)paddr->precord; + + switch (dbGetFieldIndex(paddr)) { + case indexof(VAL): + case indexof(HIHI): + case indexof(HIGH): + case indexof(LOW): + case indexof(LOLO): + case indexof(LALM): + case indexof(ALST): + case indexof(MLST): + /* do not change pre drvh/drvl behavior */ + if(prec->drvh > prec->drvl) { + pcd->upper_ctrl_limit = prec->drvh; + pcd->lower_ctrl_limit = prec->drvl; + } else { + pcd->upper_ctrl_limit = prec->hopr; + pcd->lower_ctrl_limit = prec->lopr; + } + break; + default: + recGblGetControlDouble(paddr,pcd); + } + return(0); +} + +static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad) +{ + int64outRecord *prec=(int64outRecord *)paddr->precord; + + if(dbGetFieldIndex(paddr) == indexof(VAL)) { + pad->upper_alarm_limit = prec->hihi; + pad->upper_warning_limit = prec->high; + pad->lower_warning_limit = prec->low; + pad->lower_alarm_limit = prec->lolo; + } else recGblGetAlarmDouble(paddr,pad); + return(0); +} + +static void checkAlarms(int64outRecord *prec) +{ + epicsInt64 val, hyst, lalm; + epicsInt64 alev; + epicsEnum16 asev; + + if (prec->udf) { + recGblSetSevr(prec, UDF_ALARM, prec->udfs); + return; + } + + val = prec->val; + hyst = prec->hyst; + lalm = prec->lalm; + + /* alarm condition hihi */ + asev = prec->hhsv; + alev = prec->hihi; + if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { + if (recGblSetSevr(prec, HIHI_ALARM, asev)) + prec->lalm = alev; + return; + } + + /* alarm condition lolo */ + asev = prec->llsv; + alev = prec->lolo; + if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { + if (recGblSetSevr(prec, LOLO_ALARM, asev)) + prec->lalm = alev; + return; + } + + /* alarm condition high */ + asev = prec->hsv; + alev = prec->high; + if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { + if (recGblSetSevr(prec, HIGH_ALARM, asev)) + prec->lalm = alev; + return; + } + + /* alarm condition low */ + asev = prec->lsv; + alev = prec->low; + if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { + if (recGblSetSevr(prec, LOW_ALARM, asev)) + prec->lalm = alev; + return; + } + + /* we get here only if val is out of alarm by at least hyst */ + prec->lalm = val; + return; +} + +/* DELTA calculates the absolute difference between its arguments + * expressed as an unsigned 64-bit integer */ +#define DELTA(last, val) \ + ((epicsUInt64) ((last) > (val) ? (last) - (val) : (val) - (last))) + +static void monitor(int64outRecord *prec) +{ + unsigned short monitor_mask = recGblResetAlarms(prec); + + if (prec->mdel < 0 || + DELTA(prec->mlst, prec->val) > (epicsUInt64) prec->mdel) { + /* post events for value change */ + monitor_mask |= DBE_VALUE; + /* update last value monitored */ + prec->mlst = prec->val; + } + + if (prec->adel < 0 || + DELTA(prec->alst, prec->val) > (epicsUInt64) prec->adel) { + /* post events for archive value change */ + monitor_mask |= DBE_LOG; + /* update last archive value monitored */ + prec->alst = prec->val; + } + + /* send out monitors connected to the value field */ + if (monitor_mask) + db_post_events(prec, &prec->val, monitor_mask); +} + +static long writeValue(int64outRecord *prec) +{ + long status; + struct int64outdset *pdset = (struct int64outdset *) (prec->dset); + + if (prec->pact == TRUE){ + status=(*pdset->write_int64out)(prec); + return(status); + } + + status=dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0); + if (!RTN_SUCCESS(status)) + return(status); + + if (prec->simm == menuYesNoNO){ + status=(*pdset->write_int64out)(prec); + return(status); + } + if (prec->simm == menuYesNoYES){ + status=dbPutLink(&prec->siol,DBR_INT64,&prec->val,1); + } else { + status=-1; + recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM); + return(status); + } + recGblSetSevr(prec,SIMM_ALARM,prec->sims); + + return(status); +} + +static void convert(int64outRecord *prec, epicsInt64 value) +{ + /* check drive limits */ + if(prec->drvh > prec->drvl) { + if (value > prec->drvh) value = prec->drvh; + else if (value < prec->drvl) value = prec->drvl; + } + prec->val = value; +} diff --git a/src/std/rec/int64outRecord.dbd b/src/std/rec/int64outRecord.dbd new file mode 100644 index 000000000..fc088ed69 --- /dev/null +++ b/src/std/rec/int64outRecord.dbd @@ -0,0 +1,184 @@ +#************************************************************************* +# Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* +recordtype(int64out) { + include "dbCommon.dbd" + field(VAL,DBF_INT64) { + prompt("Desired Output") + promptgroup(GUI_OUTPUT) + asl(ASL0) + pp(TRUE) + } + field(OUT,DBF_OUTLINK) { + prompt("Output Specification") + promptgroup(GUI_OUTPUT) + interest(1) + } + field(DOL,DBF_INLINK) { + prompt("Desired Output Loc") + promptgroup(GUI_OUTPUT) + interest(1) + } + field(OMSL,DBF_MENU) { + prompt("Output Mode Select") + promptgroup(GUI_OUTPUT) + interest(1) + menu(menuOmsl) + } + field(EGU,DBF_STRING) { + prompt("Units name") + promptgroup(GUI_DISPLAY) + interest(1) + size(16) + prop(YES) + } + field(DRVH,DBF_INT64) { + prompt("Drive High Limit") + promptgroup(GUI_OUTPUT) + pp(TRUE) + interest(1) + prop(YES) + } + field(DRVL,DBF_INT64) { + prompt("Drive Low Limit") + promptgroup(GUI_OUTPUT) + pp(TRUE) + interest(1) + prop(YES) + } + field(HOPR,DBF_INT64) { + prompt("High Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(LOPR,DBF_INT64) { + prompt("Low Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(HIHI,DBF_INT64) { + prompt("Hihi Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_INT64) { + prompt("Lolo Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_INT64) { + prompt("High Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_INT64) { + prompt("Low Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_INT64) { + prompt("Alarm Deadband") + promptgroup(GUI_ALARMS) + interest(1) + } + field(ADEL,DBF_INT64) { + prompt("Archive Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(MDEL,DBF_INT64) { + prompt("Monitor Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(LALM,DBF_INT64) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_INT64) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_INT64) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + field(SIOL,DBF_OUTLINK) { + prompt("Sim Output Specifctn") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup(GUI_INPUTS) + interest(2) + menu(menuAlarmSevr) + } + field(IVOA,DBF_MENU) { + prompt("INVALID output action") + promptgroup(GUI_OUTPUT) + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_INT64) { + prompt("INVALID output value") + promptgroup(GUI_OUTPUT) + interest(2) + } +} From e82449171f3179299033dc63b6336137f36b1a52 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 18 Mar 2016 17:45:52 -0500 Subject: [PATCH 06/25] Restructure cvtFastPerform, fix VxWorks build --- src/libCom/test/cvtFastPerform.cpp | 280 ++++++++++++++++------------- 1 file changed, 151 insertions(+), 129 deletions(-) diff --git a/src/libCom/test/cvtFastPerform.cpp b/src/libCom/test/cvtFastPerform.cpp index 86bbcbd8a..59de02b58 100644 --- a/src/libCom/test/cvtFastPerform.cpp +++ b/src/libCom/test/cvtFastPerform.cpp @@ -1,9 +1,9 @@ - -// Author: Jeff Hill, LANL +// Original Author: Jeff Hill, LANL #include #include #include +#include #include #include "epicsStdio.h" @@ -13,169 +13,191 @@ using namespace std; -typedef void ( * PTestFunc ) ( const double &, char * pBug, size_t bufSize ); - -class Test { +class PerfConverter { public: - Test (); - virtual ~Test (); + virtual const char *_name(void) const = 0; + virtual int _maxPrecision(void) const = 0; + virtual void _target (double srcD, float srcF, char *pDst, int prec) const = 0; + virtual ~PerfConverter () {}; +}; + +class Perf { +public: + Perf ( int maxConverters ); + virtual ~Perf (); + void addConverter( PerfConverter * c ); void execute (); protected: - char _pDst[128]; - double _srcDbl; - float _srcFlt; - unsigned short _prec; static unsigned const _nUnrolled = 10; static const unsigned _uSecPerSec = 1000000; static unsigned const _nIterations = 10000; - virtual const char *_name(void) = 0; - virtual int _maxPrecision(void) = 0; - virtual void _target () = 0; - void _measure (); - Test ( const Test & ); - Test & operator = ( Test & ); + + const int _maxConverters; + PerfConverter **_converters; + int _nConverters; + int _maxPrecision; + + void _measure ( double srcD, float srcF, int prec ); + +private: + Perf ( const Perf & ); + Perf & operator = ( Perf & ); }; -class TestCvtFastFloat : public Test { -protected: - void _target (); - const char *_name (void) { return "cvtFloatToString"; } - int _maxPrecision(void) { return 12; } -}; - -class TestCvtFastDouble : public Test { -protected: - void _target (void); - const char *_name (void) { return "cvtDoubleToString"; } - int _maxPrecision(void) { return 17; } -}; - -class TestSNPrintf : public Test { -protected: - void _target (); - const char *_name (void) { return "epicsSnprintf"; } - int _maxPrecision(void) { return 17; } -}; - -Test :: - Test () : - _srcDbl ( 0.0 ), _prec ( 0 ) +Perf :: Perf ( int maxConverters ) : + _maxConverters ( maxConverters ), + _converters ( new PerfConverter * [ maxConverters ] ), + _nConverters ( 0 ), + _maxPrecision ( 0 ) { } -Test :: ~Test () +Perf :: ~Perf () { + for ( int j = 0; j < _nConverters; j++ ) + delete _converters[ j ]; + + delete [] _converters; } -void Test :: execute () +void Perf :: addConverter(PerfConverter *c) +{ + if ( _nConverters >= _maxConverters ) + throw std :: runtime_error ( "Too many converters" ); + + _converters[ _nConverters++ ] = c; + + int prec = c->_maxPrecision(); + if ( prec > _maxPrecision ) + _maxPrecision = prec; +} + +void Perf :: execute () { - for ( unsigned i = 0; i < 3; i++ ) { double mVal = rand (); mVal /= (RAND_MAX + 1.0); double eVal = rand (); eVal /= (RAND_MAX + 1.0); + double dVal = eVal; - dVal *= DBL_MAX_EXP - DBL_MIN_EXP; - dVal += DBL_MIN_EXP; + dVal *= FLT_MAX_EXP - FLT_MIN_EXP; + dVal += FLT_MIN_EXP; int dEVal = static_cast < int > ( dVal + 0.5 ); - float fVal = eVal; - fVal *= FLT_MAX_EXP - FLT_MIN_EXP; - fVal += FLT_MIN_EXP; - int fEVal = static_cast < int > ( fVal + 0.5 ); - _srcDbl = ldexp ( mVal, dEVal ); - _srcFlt = ldexpf ( mVal, fEVal ); - for ( _prec = 0; _prec <= _maxPrecision(); _prec++ ) { - _measure (); + double srcDbl = ldexp ( mVal, dEVal ); + float srcFlt = (float) srcDbl; + + for ( int prec = 0; prec <= _maxPrecision; prec++ ) { + _measure (srcFlt, srcDbl, prec); } - _srcDbl = rand (); - _srcDbl /= (RAND_MAX + 1.0); - _srcDbl *= 10.0; - _srcDbl -= 5.0; - _srcFlt = (float) _srcDbl; - for ( _prec = 0; _prec <= _maxPrecision(); _prec++ ) { - _measure (); + + srcDbl = rand (); + srcDbl /= (RAND_MAX + 1.0); + srcDbl *= 10.0; + srcDbl -= 5.0; + srcFlt = (float) srcDbl; + + for ( int prec = 0; prec <= _maxPrecision; prec++ ) { + _measure (srcFlt, srcDbl, prec); } } } -void Test :: _measure () +void Perf :: _measure (double srcD, float srcF, int prec) { - epicsTime beg = epicsTime :: getCurrent (); - for ( unsigned i = 0; i < _nIterations; i++ ) { - _target (); + char pDst[40]; + + for ( int j = 0; j < _nConverters; j++ ) { + const PerfConverter *c = _converters[j]; + + if (prec > c->_maxPrecision()) + continue; + + epicsTime beg = epicsTime :: getCurrent (); + for ( unsigned i = 0; i < _nIterations; i++ ) { + c->_target (srcD, srcF, pDst, prec); + } + epicsTime end = epicsTime :: getCurrent (); + + double elapsed = end - beg; + elapsed /= _nIterations * _nUnrolled; + printf ( "%17s: %11.9f sec, prec=%2i '%s'\n", + c->_name (), elapsed, prec, pDst ); } - epicsTime end = epicsTime :: getCurrent (); - double elapsed = end - beg; - elapsed /= _nIterations * _nUnrolled; - printf ( "%17s: %12.9f sec, prec=%2i, out=%s\n", - this->_name (), elapsed, _prec, _pDst ); -} - -void TestCvtFastFloat :: _target () -{ - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); - cvtFloatToString ( _srcFlt, _pDst, _prec ); } -void TestCvtFastDouble :: _target () -{ - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); +class PerfCvtFastFloat : public PerfConverter { +public: + const char *_name (void) const { return "cvtFloatToString"; } + int _maxPrecision (void) const { return 12; } + void _target (double srcD, float srcF, char *pDst, int prec) const + { + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); - cvtDoubleToString ( _srcDbl, _pDst, _prec ); -} + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, pDst, prec ); + } +}; + + +class PerfCvtFastDouble : public PerfConverter { +public: + const char *_name (void) const { return "cvtDoubleToString"; } + int _maxPrecision (void) const { return 17; } + void _target (double srcD, float srcF, char *pDst, int prec) const + { + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, pDst, prec ); + } +}; + + +class PerfSNPrintf : public PerfConverter { +public: + const char *_name (void) const { return "epicsSnprintf"; } + int _maxPrecision (void) const { return 17; } + void _target (double srcD, float srcF, char *pDst, int prec) const + { + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + } +}; -void TestSNPrintf :: _target () -{ - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); - epicsSnprintf ( _pDst, sizeof ( _pDst ), "%.*g", - static_cast < int > ( _prec ), _srcDbl ); -} MAIN(cvtFastPerform) { - TestCvtFastFloat testCvtFastFloat; - TestCvtFastDouble testCvtFastDouble; - TestSNPrintf testSNPrintf; - - testCvtFastFloat.execute (); - testCvtFastDouble.execute (); - testSNPrintf.execute (); + Perf t(3); + + t.addConverter( new PerfCvtFastFloat ); + t.addConverter( new PerfCvtFastDouble ); + t.addConverter( new PerfSNPrintf ); + + t.execute (); return 0; } From db4f208659d1893af429c762ecac8cbfc02a7dfa Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 22 Mar 2016 01:01:51 -0500 Subject: [PATCH 07/25] Collate and report by precision --- src/libCom/test/cvtFastPerform.cpp | 56 ++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/libCom/test/cvtFastPerform.cpp b/src/libCom/test/cvtFastPerform.cpp index 59de02b58..164643965 100644 --- a/src/libCom/test/cvtFastPerform.cpp +++ b/src/libCom/test/cvtFastPerform.cpp @@ -18,6 +18,8 @@ public: virtual const char *_name(void) const = 0; virtual int _maxPrecision(void) const = 0; virtual void _target (double srcD, float srcF, char *pDst, int prec) const = 0; + virtual void _add(int prec, double elapsed) = 0; + virtual double _total(int prec) const = 0; virtual ~PerfConverter () {}; }; @@ -27,6 +29,7 @@ public: virtual ~Perf (); void addConverter( PerfConverter * c ); void execute (); + void report (const char *title, int count); protected: static unsigned const _nUnrolled = 10; static const unsigned _uSecPerSec = 1000000; @@ -74,7 +77,9 @@ void Perf :: addConverter(PerfConverter *c) void Perf :: execute () { - for ( unsigned i = 0; i < 3; i++ ) { + const int count = 10; + + for ( unsigned i = 0; i < count; i++ ) { double mVal = rand (); mVal /= (RAND_MAX + 1.0); double eVal = rand (); @@ -90,17 +95,43 @@ void Perf :: execute () for ( int prec = 0; prec <= _maxPrecision; prec++ ) { _measure (srcFlt, srcDbl, prec); } + } + report ( "Random Exponent", count ); - srcDbl = rand (); + for ( unsigned i = 0; i < count; i++ ) { + double srcDbl = rand (); srcDbl /= (RAND_MAX + 1.0); srcDbl *= 10.0; srcDbl -= 5.0; - srcFlt = (float) srcDbl; + float srcFlt = (float) srcDbl; for ( int prec = 0; prec <= _maxPrecision; prec++ ) { _measure (srcFlt, srcDbl, prec); } } + report ( "-5..+5", count ); +} + +void Perf :: report (const char *title, int count) +{ + printf( "\n%s\n\nprec\t", title ); + for ( int j = 0; j < _nConverters; j++ ) + printf( "%-17s ", _converters[j]->_name() ); + + for (int prec = 0; prec < _maxPrecision; prec++ ) { + printf( "\n %2d\t", prec ); + for (int j = 0; j < _nConverters; j++ ) { + PerfConverter *c = _converters[j]; + if (prec > c->_maxPrecision()) + printf( "%11s ", "-" ); + else { + double total = c->_total(prec); + printf( "%11.9f sec ", c->_total(prec) / count ); + c->_add(prec, -total); // Reset counter + } + } + } + printf( "\n\n" ); } void Perf :: _measure (double srcD, float srcF, int prec) @@ -108,7 +139,7 @@ void Perf :: _measure (double srcD, float srcF, int prec) char pDst[40]; for ( int j = 0; j < _nConverters; j++ ) { - const PerfConverter *c = _converters[j]; + PerfConverter *c = _converters[j]; if (prec > c->_maxPrecision()) continue; @@ -121,8 +152,9 @@ void Perf :: _measure (double srcD, float srcF, int prec) double elapsed = end - beg; elapsed /= _nIterations * _nUnrolled; - printf ( "%17s: %11.9f sec, prec=%2i '%s'\n", - c->_name (), elapsed, prec, pDst ); + c->_add( prec, elapsed ); + // printf ( "%17s: %11.9f sec, prec=%2i '%s'\n", + // c->_name (), elapsed, prec, pDst ); } } @@ -144,6 +176,10 @@ public: cvtFloatToString ( srcF, pDst, prec ); cvtFloatToString ( srcF, pDst, prec ); } + void _add(int prec, double elapsed) { _measured[prec] += elapsed; } + double _total (int prec) const { return _measured[prec]; } +private: + double _measured[13]; }; @@ -165,6 +201,10 @@ public: cvtDoubleToString ( srcD, pDst, prec ); cvtDoubleToString ( srcD, pDst, prec ); } + void _add(int prec, double elapsed) { _measured[prec] += elapsed; } + double _total (int prec) const { return _measured[prec]; } +private: + double _measured[18]; }; @@ -186,6 +226,10 @@ public: epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); } + void _add(int prec, double elapsed) { _measured[prec] += elapsed; } + double _total (int prec) const { return _measured[prec]; } +private: + double _measured[18]; }; From d949e34c138d204ea5d8e0a795992dab270f22db Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 22 Mar 2016 17:47:03 -0500 Subject: [PATCH 08/25] More cvtFastPerform changes Added a converter using std::streambuf (slow!) Pass buffer size to converters Added verbose flag and # numbers to measure Do the small number tests first --- src/libCom/test/cvtFastPerform.cpp | 197 +++++++++++++++++++---------- 1 file changed, 127 insertions(+), 70 deletions(-) diff --git a/src/libCom/test/cvtFastPerform.cpp b/src/libCom/test/cvtFastPerform.cpp index 164643965..cb0d64c9d 100644 --- a/src/libCom/test/cvtFastPerform.cpp +++ b/src/libCom/test/cvtFastPerform.cpp @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include "epicsStdio.h" #include "cvtFast.h" @@ -17,7 +19,7 @@ class PerfConverter { public: virtual const char *_name(void) const = 0; virtual int _maxPrecision(void) const = 0; - virtual void _target (double srcD, float srcF, char *pDst, int prec) const = 0; + virtual void _target (double srcD, float srcF, char *dst, size_t len, int prec) const = 0; virtual void _add(int prec, double elapsed) = 0; virtual double _total(int prec) const = 0; virtual ~PerfConverter () {}; @@ -28,7 +30,7 @@ public: Perf ( int maxConverters ); virtual ~Perf (); void addConverter( PerfConverter * c ); - void execute (); + void execute (int count, bool verbose); void report (const char *title, int count); protected: static unsigned const _nUnrolled = 10; @@ -39,6 +41,7 @@ protected: PerfConverter **_converters; int _nConverters; int _maxPrecision; + bool _verbose; void _measure ( double srcD, float srcF, int prec ); @@ -75,11 +78,24 @@ void Perf :: addConverter(PerfConverter *c) _maxPrecision = prec; } -void Perf :: execute () +void Perf :: execute (int count, bool verbose) { - const int count = 10; + _verbose = verbose; - for ( unsigned i = 0; i < count; i++ ) { + for ( int i = 0; i < count; i++ ) { + double srcDbl = rand (); + srcDbl /= (RAND_MAX + 1.0); + srcDbl *= 20.0; + srcDbl -= 10.0; + float srcFlt = (float) srcDbl; + + for ( int prec = 0; prec <= _maxPrecision; prec++ ) { + _measure (srcFlt, srcDbl, prec); + } + } + report ( "Small numbers, -10..+10", count ); + + for ( int i = 0; i < count; i++ ) { double mVal = rand (); mVal /= (RAND_MAX + 1.0); double eVal = rand (); @@ -96,47 +112,34 @@ void Perf :: execute () _measure (srcFlt, srcDbl, prec); } } - report ( "Random Exponent", count ); - - for ( unsigned i = 0; i < count; i++ ) { - double srcDbl = rand (); - srcDbl /= (RAND_MAX + 1.0); - srcDbl *= 10.0; - srcDbl -= 5.0; - float srcFlt = (float) srcDbl; - - for ( int prec = 0; prec <= _maxPrecision; prec++ ) { - _measure (srcFlt, srcDbl, prec); - } - } - report ( "-5..+5", count ); + report ( "Random mantissa+exponent", count ); } void Perf :: report (const char *title, int count) { printf( "\n%s\n\nprec\t", title ); for ( int j = 0; j < _nConverters; j++ ) - printf( "%-17s ", _converters[j]->_name() ); + printf( "%-16s ", _converters[j]->_name() ); - for (int prec = 0; prec < _maxPrecision; prec++ ) { - printf( "\n %2d\t", prec ); + for (int prec = 0; prec <= _maxPrecision; prec++ ) { + printf( "\n %2d\t", prec ); for (int j = 0; j < _nConverters; j++ ) { PerfConverter *c = _converters[j]; - if (prec > c->_maxPrecision()) - printf( "%11s ", "-" ); - else { - double total = c->_total(prec); - printf( "%11.9f sec ", c->_total(prec) / count ); - c->_add(prec, -total); // Reset counter - } - } + if (prec > c->_maxPrecision()) + printf( "%11s ", "-" ); + else { + double total = c->_total(prec); + printf( "%11.9f sec ", c->_total(prec) / count ); + c->_add(prec, -total); // Reset counter + } + } } printf( "\n\n" ); } void Perf :: _measure (double srcD, float srcF, int prec) { - char pDst[40]; + char buf[40]; for ( int j = 0; j < _nConverters; j++ ) { PerfConverter *c = _converters[j]; @@ -144,17 +147,21 @@ void Perf :: _measure (double srcD, float srcF, int prec) if (prec > c->_maxPrecision()) continue; + std::memset(buf, 0, sizeof(buf)); + epicsTime beg = epicsTime :: getCurrent (); for ( unsigned i = 0; i < _nIterations; i++ ) { - c->_target (srcD, srcF, pDst, prec); + c->_target (srcD, srcF, buf, sizeof(buf), prec); } epicsTime end = epicsTime :: getCurrent (); double elapsed = end - beg; elapsed /= _nIterations * _nUnrolled; - c->_add( prec, elapsed ); - // printf ( "%17s: %11.9f sec, prec=%2i '%s'\n", - // c->_name (), elapsed, prec, pDst ); + c->_add( prec, elapsed ); + + if (_verbose) + printf ( "%17s: %11.9f sec, prec=%2i '%s'\n", + c->_name (), elapsed, prec, buf ); } } @@ -162,19 +169,19 @@ class PerfCvtFastFloat : public PerfConverter { public: const char *_name (void) const { return "cvtFloatToString"; } int _maxPrecision (void) const { return 12; } - void _target (double srcD, float srcF, char *pDst, int prec) const + void _target (double srcD, float srcF, char *dst, size_t len, int prec) const { - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); - cvtFloatToString ( srcF, pDst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); + cvtFloatToString ( srcF, dst, prec ); } void _add(int prec, double elapsed) { _measured[prec] += elapsed; } double _total (int prec) const { return _measured[prec]; } @@ -187,19 +194,19 @@ class PerfCvtFastDouble : public PerfConverter { public: const char *_name (void) const { return "cvtDoubleToString"; } int _maxPrecision (void) const { return 17; } - void _target (double srcD, float srcF, char *pDst, int prec) const + void _target (double srcD, float srcF, char *dst, size_t len, int prec) const { - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); - cvtDoubleToString ( srcD, pDst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); + cvtDoubleToString ( srcD, dst, prec ); } void _add(int prec, double elapsed) { _measured[prec] += elapsed; } double _total (int prec) const { return _measured[prec]; } @@ -212,19 +219,66 @@ class PerfSNPrintf : public PerfConverter { public: const char *_name (void) const { return "epicsSnprintf"; } int _maxPrecision (void) const { return 17; } - void _target (double srcD, float srcF, char *pDst, int prec) const + void _target (double srcD, float srcF, char *dst, size_t len, int prec) const { - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); - epicsSnprintf ( pDst, 39, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + epicsSnprintf ( dst, len, "%.*g", prec, srcD ); + } + void _add(int prec, double elapsed) { _measured[prec] += elapsed; } + double _total (int prec) const { return _measured[prec]; } +private: + double _measured[18]; +}; + + +// This is a quick-and-dirty std::streambuf converter that writes directly +// into the output buffer. Performance is slower than epicsSnprintf(). + +struct membuf: public std::streambuf { + membuf(char *array, size_t size) { + this->setp(array, array + size - 1); + } +}; + +struct omemstream: virtual membuf, std::ostream { + omemstream(char *array, size_t size): + membuf(array, size), + std::ostream(this) { + } +}; + +static void ossConvertD(char *dst, size_t len, int prec, double src) { + omemstream oss(dst, len); + oss.precision(prec); + oss << src << ends; +} + +class PerfStreamBuf : public PerfConverter { +public: + const char *_name (void) const { return "std::streambuf"; } + int _maxPrecision (void) const { return 17; } + void _target (double srcD, float srcF, char *dst, size_t len, int prec) const + { + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); + ossConvertD ( dst, len, prec, srcD ); } void _add(int prec, double elapsed) { _measured[prec] += elapsed; } double _total (int prec) const { return _measured[prec]; } @@ -235,13 +289,16 @@ private: MAIN(cvtFastPerform) { - Perf t(3); + Perf t(4); t.addConverter( new PerfCvtFastFloat ); t.addConverter( new PerfCvtFastDouble ); t.addConverter( new PerfSNPrintf ); + t.addConverter( new PerfStreamBuf ); - t.execute (); + // count = number of different random numbers to measure + // verbose = whether to display individual measurements + t.execute (10, false); return 0; } From 0a0b9a93a2f0b7f0047e42c65f995d14e28cc6fc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 22 Mar 2016 18:14:12 -0500 Subject: [PATCH 09/25] Simplify epicsConvertDoubleToFloat() --- src/libCom/misc/epicsConvert.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/libCom/misc/epicsConvert.c b/src/libCom/misc/epicsConvert.c index 11778c33a..9318ceb7e 100644 --- a/src/libCom/misc/epicsConvert.c +++ b/src/libCom/misc/epicsConvert.c @@ -18,28 +18,18 @@ epicsShareFunc float epicsConvertDoubleToFloat(double value) { - float rtnvalue; + double abs; - if (value == 0) { - rtnvalue = 0; - } else if (!finite(value)) { - rtnvalue = (float)value; - } else { - double abs = fabs(value); + if (value == 0 || !finite(value)) + return (float) value; - if (abs >= FLT_MAX) { - if (value > 0) - rtnvalue = FLT_MAX; - else - rtnvalue = -FLT_MAX; - } else if (abs <= FLT_MIN) { - if (value > 0) - rtnvalue = FLT_MIN; - else - rtnvalue = -FLT_MIN; - } else { - rtnvalue = (float)value; - } - } - return rtnvalue; + abs = fabs(value); + + if (abs >= FLT_MAX) + return (value > 0) ? FLT_MAX : -FLT_MAX; + + if (abs <= FLT_MIN) + return (value > 0) ? FLT_MIN : -FLT_MIN; + + return (float) value; } From bc2a47b84971ab308150d418b99c27db67afda8d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 23 Mar 2016 16:56:34 -0500 Subject: [PATCH 10/25] cvtFastPerform: Rename reserved member names, fix for vxWorks --- src/libCom/test/cvtFastPerform.cpp | 207 ++++++++++++++++++----------- 1 file changed, 127 insertions(+), 80 deletions(-) diff --git a/src/libCom/test/cvtFastPerform.cpp b/src/libCom/test/cvtFastPerform.cpp index cb0d64c9d..c3f99dc61 100644 --- a/src/libCom/test/cvtFastPerform.cpp +++ b/src/libCom/test/cvtFastPerform.cpp @@ -17,11 +17,11 @@ using namespace std; class PerfConverter { public: - virtual const char *_name(void) const = 0; - virtual int _maxPrecision(void) const = 0; - virtual void _target (double srcD, float srcF, char *dst, size_t len, int prec) const = 0; - virtual void _add(int prec, double elapsed) = 0; - virtual double _total(int prec) const = 0; + virtual const char * name(void) const = 0; + virtual int maxPrecision(void) const = 0; + virtual void target (double srcD, float srcF, char *dst, size_t len, int prec) const = 0; + virtual void add(int prec, double elapsed) = 0; + virtual double total(int prec) = 0; virtual ~PerfConverter () {}; }; @@ -33,54 +33,54 @@ public: void execute (int count, bool verbose); void report (const char *title, int count); protected: - static unsigned const _nUnrolled = 10; - static const unsigned _uSecPerSec = 1000000; - static unsigned const _nIterations = 10000; + static unsigned const nUnrolled = 10; + static const unsigned uSecPerSec = 1000000; + static unsigned const nIterations = 10000; - const int _maxConverters; - PerfConverter **_converters; - int _nConverters; - int _maxPrecision; - bool _verbose; + const int maxConverters; + PerfConverter **converters; + int nConverters; + int maxPrecision; + bool verbose; - void _measure ( double srcD, float srcF, int prec ); + void measure ( double srcD, float srcF, int prec ); private: Perf ( const Perf & ); Perf & operator = ( Perf & ); }; -Perf :: Perf ( int maxConverters ) : - _maxConverters ( maxConverters ), - _converters ( new PerfConverter * [ maxConverters ] ), - _nConverters ( 0 ), - _maxPrecision ( 0 ) +Perf :: Perf ( int maxConverters_ ) : + maxConverters ( maxConverters_ ), + converters ( new PerfConverter * [ maxConverters_ ] ), + nConverters ( 0 ), + maxPrecision ( 0 ) { } Perf :: ~Perf () { - for ( int j = 0; j < _nConverters; j++ ) - delete _converters[ j ]; + for ( int j = 0; j < nConverters; j++ ) + delete converters[ j ]; - delete [] _converters; + delete [] converters; } void Perf :: addConverter(PerfConverter *c) { - if ( _nConverters >= _maxConverters ) + if ( nConverters >= maxConverters ) throw std :: runtime_error ( "Too many converters" ); - _converters[ _nConverters++ ] = c; + converters[ nConverters++ ] = c; - int prec = c->_maxPrecision(); - if ( prec > _maxPrecision ) - _maxPrecision = prec; + int prec = c->maxPrecision(); + if ( prec > maxPrecision ) + maxPrecision = prec; } -void Perf :: execute (int count, bool verbose) +void Perf :: execute (const int count, bool verbose_) { - _verbose = verbose; + verbose = verbose_; for ( int i = 0; i < count; i++ ) { double srcDbl = rand (); @@ -89,8 +89,8 @@ void Perf :: execute (int count, bool verbose) srcDbl -= 10.0; float srcFlt = (float) srcDbl; - for ( int prec = 0; prec <= _maxPrecision; prec++ ) { - _measure (srcFlt, srcDbl, prec); + for ( int prec = 0; prec <= maxPrecision; prec++ ) { + measure (srcFlt, srcDbl, prec); } } report ( "Small numbers, -10..+10", count ); @@ -108,68 +108,75 @@ void Perf :: execute (int count, bool verbose) double srcDbl = ldexp ( mVal, dEVal ); float srcFlt = (float) srcDbl; - for ( int prec = 0; prec <= _maxPrecision; prec++ ) { - _measure (srcFlt, srcDbl, prec); + for ( int prec = 0; prec <= maxPrecision; prec++ ) { + measure (srcFlt, srcDbl, prec); } } report ( "Random mantissa+exponent", count ); } -void Perf :: report (const char *title, int count) +void Perf :: report (const char *title, const int count) { printf( "\n%s\n\nprec\t", title ); - for ( int j = 0; j < _nConverters; j++ ) - printf( "%-16s ", _converters[j]->_name() ); + for ( int j = 0; j < nConverters; j++ ) + printf( "%-16s ", converters[j]->name() ); - for (int prec = 0; prec <= _maxPrecision; prec++ ) { + for (int prec = 0; prec <= maxPrecision; prec++ ) { printf( "\n %2d\t", prec ); - for (int j = 0; j < _nConverters; j++ ) { - PerfConverter *c = _converters[j]; - if (prec > c->_maxPrecision()) + for (int j = 0; j < nConverters; j++ ) { + PerfConverter *c = converters[j]; + if (prec > c->maxPrecision()) printf( "%11s ", "-" ); else { - double total = c->_total(prec); - printf( "%11.9f sec ", c->_total(prec) / count ); - c->_add(prec, -total); // Reset counter + printf( "%11.9f sec ", c->total(prec) / count ); } } } printf( "\n\n" ); } -void Perf :: _measure (double srcD, float srcF, int prec) +void Perf :: measure (double srcD, float srcF, int prec) { char buf[40]; - for ( int j = 0; j < _nConverters; j++ ) { - PerfConverter *c = _converters[j]; + for ( int j = 0; j < nConverters; j++ ) { + PerfConverter *c = converters[j]; - if (prec > c->_maxPrecision()) + if (prec > c->maxPrecision()) continue; std::memset(buf, 0, sizeof(buf)); epicsTime beg = epicsTime :: getCurrent (); - for ( unsigned i = 0; i < _nIterations; i++ ) { - c->_target (srcD, srcF, buf, sizeof(buf), prec); + for ( unsigned i = 0; i < nIterations; i++ ) { + c->target (srcD, srcF, buf, sizeof(buf) - 1, prec); } epicsTime end = epicsTime :: getCurrent (); double elapsed = end - beg; - elapsed /= _nIterations * _nUnrolled; - c->_add( prec, elapsed ); + elapsed /= nIterations * nUnrolled; + c->add( prec, elapsed ); - if (_verbose) + if (verbose) printf ( "%17s: %11.9f sec, prec=%2i '%s'\n", - c->_name (), elapsed, prec, buf ); + c->name (), elapsed, prec, buf ); } } + +// Conversions to be measured + class PerfCvtFastFloat : public PerfConverter { + static const int digits = 12; public: - const char *_name (void) const { return "cvtFloatToString"; } - int _maxPrecision (void) const { return 12; } - void _target (double srcD, float srcF, char *dst, size_t len, int prec) const + PerfCvtFastFloat () + { + for (int i = 0; i <= digits; i++) + measured[i] = 0; // Some targets seem to need this + } + int maxPrecision (void) const { return digits; } + const char *name (void) const { return "cvtFloatToString"; } + void target (double srcD, float srcF, char *dst, size_t len, int prec) const { cvtFloatToString ( srcF, dst, prec ); cvtFloatToString ( srcF, dst, prec ); @@ -183,18 +190,28 @@ public: cvtFloatToString ( srcF, dst, prec ); cvtFloatToString ( srcF, dst, prec ); } - void _add(int prec, double elapsed) { _measured[prec] += elapsed; } - double _total (int prec) const { return _measured[prec]; } + void add (int prec, double elapsed) { measured[prec] += elapsed; } + double total (int prec) { + double total = measured[prec]; + measured[prec] = 0; + return total; + } private: - double _measured[13]; + double measured[digits+1]; }; class PerfCvtFastDouble : public PerfConverter { + static const int digits = 17; public: - const char *_name (void) const { return "cvtDoubleToString"; } - int _maxPrecision (void) const { return 17; } - void _target (double srcD, float srcF, char *dst, size_t len, int prec) const + PerfCvtFastDouble () + { + for (int i = 0; i <= digits; i++) + measured[i] = 0; // Some targets seem to need this + } + int maxPrecision (void) const { return digits; } + const char *name (void) const { return "cvtDoubleToString"; } + void target (double srcD, float srcF, char *dst, size_t len, int prec) const { cvtDoubleToString ( srcD, dst, prec ); cvtDoubleToString ( srcD, dst, prec ); @@ -208,18 +225,28 @@ public: cvtDoubleToString ( srcD, dst, prec ); cvtDoubleToString ( srcD, dst, prec ); } - void _add(int prec, double elapsed) { _measured[prec] += elapsed; } - double _total (int prec) const { return _measured[prec]; } + void add(int prec, double elapsed) { measured[prec] += elapsed; } + double total (int prec) { + double total = measured[prec]; + measured[prec] = 0; + return total; + } private: - double _measured[18]; + double measured[digits+1]; }; class PerfSNPrintf : public PerfConverter { + static const int digits = 17; public: - const char *_name (void) const { return "epicsSnprintf"; } - int _maxPrecision (void) const { return 17; } - void _target (double srcD, float srcF, char *dst, size_t len, int prec) const + PerfSNPrintf () + { + for (int i = 0; i <= digits; i++) + measured[i] = 0; // Some targets seem to need this + } + int maxPrecision (void) const { return digits; } + const char *name (void) const { return "epicsSnprintf"; } + void target (double srcD, float srcF, char *dst, size_t len, int prec) const { epicsSnprintf ( dst, len, "%.*g", prec, srcD ); epicsSnprintf ( dst, len, "%.*g", prec, srcD ); @@ -233,10 +260,14 @@ public: epicsSnprintf ( dst, len, "%.*g", prec, srcD ); epicsSnprintf ( dst, len, "%.*g", prec, srcD ); } - void _add(int prec, double elapsed) { _measured[prec] += elapsed; } - double _total (int prec) const { return _measured[prec]; } + void add(int prec, double elapsed) { measured[prec] += elapsed; } + double total (int prec) { + double total = measured[prec]; + measured[prec] = 0; + return total; + } private: - double _measured[18]; + double measured[digits+1]; }; @@ -263,10 +294,16 @@ static void ossConvertD(char *dst, size_t len, int prec, double src) { } class PerfStreamBuf : public PerfConverter { + static const int digits = 17; public: - const char *_name (void) const { return "std::streambuf"; } - int _maxPrecision (void) const { return 17; } - void _target (double srcD, float srcF, char *dst, size_t len, int prec) const + PerfStreamBuf () + { + for (int i = 0; i <= digits; i++) + measured[i] = 0; // Some targets seem to need this + } + int maxPrecision (void) const { return digits; } + const char *name (void) const { return "std::streambuf"; } + void target (double srcD, float srcF, char *dst, size_t len, int prec) const { ossConvertD ( dst, len, prec, srcD ); ossConvertD ( dst, len, prec, srcD ); @@ -280,10 +317,14 @@ public: ossConvertD ( dst, len, prec, srcD ); ossConvertD ( dst, len, prec, srcD ); } - void _add(int prec, double elapsed) { _measured[prec] += elapsed; } - double _total (int prec) const { return _measured[prec]; } + void add(int prec, double elapsed) { measured[prec] += elapsed; } + double total (int prec) { + double total = measured[prec]; + measured[prec] = 0; + return total; + } private: - double _measured[18]; + double measured[digits+1]; }; @@ -296,9 +337,15 @@ MAIN(cvtFastPerform) t.addConverter( new PerfSNPrintf ); t.addConverter( new PerfStreamBuf ); - // count = number of different random numbers to measure - // verbose = whether to display individual measurements - t.execute (10, false); + // The parameter to execute() below are: + // count = number of different random numbers to measure + // verbose = whether to display individual measurements + +#ifdef vxWorks + t.execute (3, true); // Slow... +#else + t.execute (5, false); +#endif return 0; } From d33c402b00759b655580f1d4a0a761d594bd635d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 23 Mar 2016 17:15:57 -0500 Subject: [PATCH 11/25] Release Notes --- documentation/RELEASE_NOTES.html | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 372f32d7d..e919d402c 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -21,6 +21,46 @@ --> +

IOC Database Support for 64-bit integers

+ +

The IOC now supports the 64-bit integer field types DBF_INT64 and +DBF_UINT64, and there are new record types int64in and +int64out derived from the longin and longout types +respectively that use the DBF_INT64 data type for their VAL and related +fields. The usual range of Soft Channel device support are included for these +new record types.

+ +

All internal IOC APIs such as dbAccess can handle the new field types and +their associated request values DBR_INT64 and DBR_UINT64, +which are implemented using the epicsInt64 and epicsUInt64 +typedef's from the epicsTypes.h header.

+ +

The waveform record type has been updated to support these new field types. +All waveform device support layers must be updated to recognize the new +type enumeration values, which had to be inserted before the +FLOAT value in the enum dbfType and in menuFtype. C +or C++ code can detect at compile-time whether this version of base provides +64-bit support by checking for the presence of the DBR_INT64 macro as +follows (Note that DBF_INT64 is an enum tag and not a +preprocessor macro):

+ +
+#ifdef DBR_INT64
+    /* Code where Base has INT64 support */
+#else
+    /* Code for older versions */
+#endif
+
+ +

Channel Access does not (and probably never will) directly support 64-bit +integer types, so the new field types are presented to the CA server as +DBF_DOUBLE values. This means that field values larger than 2^52 +(0x10_0000_0000_0000 = 4503599627370496) cannot be transported over Channel +Access without their least significant bits being truncated. The EPICS V4 +pvAccess network protocol can transport 64-bit data types however, and +a future release of the pvaSrv module will connect this ability to the IOC.

+ +

Echoless comments in iocsh

The way comments are parsed by the iocsh interpreter has changed. The From 0821c8c4ff97336911eb81263ee7dcd97481151f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 12 Sep 2016 18:20:02 -0400 Subject: [PATCH 12/25] dbStatic: dbPutStringNum(, "") not an error Restore previous behavour that empty string is equivalent to numeric zero. epicsParse*() returns S_stdlib_noConversion where previously strtoul() did not. Conflicts: src/ioc/db/test/Makefile --- src/ioc/db/test/Makefile | 8 +++- src/ioc/db/test/dbPutGetTest.c | 69 +++++++++++++++++++++++++++++++++ src/ioc/db/test/dbPutGetTest.db | 31 +++++++++++++++ src/ioc/dbStatic/dbStaticRun.c | 4 ++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/ioc/db/test/dbPutGetTest.c create mode 100644 src/ioc/db/test/dbPutGetTest.db diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 67ef688e0..da3bc035e 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -152,7 +152,13 @@ recGblCheckDeadbandTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp testHarness_SRCS += recGblCheckDeadbandTest.c TESTS += recGblCheckDeadbandTest -# The testHarness runs all the test programs in a known working order. +TESTPROD_HOST += testPutGetTest +testPutGetTest_SRCS += dbPutGetTest.c +testPutGetTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += dbPutGetTest.db +TESTS += testPutGetTest + +# This runs all the test programs in a known working order: testHarness_SRCS += epicsRunDbTests.c dbTestHarness_SRCS += $(testHarness_SRCS) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c new file mode 100644 index 000000000..b9729940d --- /dev/null +++ b/src/ioc/db/test/dbPutGetTest.c @@ -0,0 +1,69 @@ + +#include + +#include +#include +#include +#include +#include + +static +void testdbGetStringEqual(const char *pv, const char *expected) +{ + const char *actual; + int ok; + DBENTRY ent; + + dbInitEntry(pdbbase, &ent); + + if(dbFindRecord(&ent, pv)) { + testFail("Failed to find record '%s'", pv); + return; + } + + actual = dbGetString(&ent); + ok = (!actual && !expected) + || (actual && expected && strcmp(actual, expected)==0); + + testOk(ok, "dbGetString(\"%s\") -> \"%s\" == \"%s\"", pv, actual, expected); + + dbFinishEntry(&ent); +} + +static +void testGetString(void) +{ + testDiag("testGetString()"); + + testdbGetStringEqual("recempty.DTYP", "Soft Channel"); + testdbGetStringEqual("recempty.DESC", ""); + testdbGetStringEqual("recempty.PHAS", "0"); + testdbGetStringEqual("recempty.TSE" , "0"); + testdbGetStringEqual("recempty.DISA", "0"); + testdbGetStringEqual("recempty.DISV", "0"); + + testdbGetStringEqual("recoverwrite.DTYP", "Soft Channel"); + testdbGetStringEqual("recoverwrite.DESC", ""); + testdbGetStringEqual("recoverwrite.PHAS", "0"); + testdbGetStringEqual("recoverwrite.TSE" , "0"); + testdbGetStringEqual("recoverwrite.DISA", "0"); + testdbGetStringEqual("recoverwrite.DISV", "0"); +} + +void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); + +MAIN(dbPutGet) +{ + testPlan(0); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + dbTestIoc_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase("dbPutGetTest.db", NULL, NULL); + + testGetString(); + + testdbCleanup(); + + return testDone(); +} diff --git a/src/ioc/db/test/dbPutGetTest.db b/src/ioc/db/test/dbPutGetTest.db new file mode 100644 index 000000000..06a520c60 --- /dev/null +++ b/src/ioc/db/test/dbPutGetTest.db @@ -0,0 +1,31 @@ + +record(x, "recempty") { +# empty string is the same "0" for numeric fields + field(DTYP, "") + field(DESC, "") + field(PHAS, "") + field(TSE , "") + field(DISA, "") + field(DISV, "") +} + +record(x, "recoverwrite") { +# first with non-default values + field(DTYP, "Scan I/O") + field(DESC, "hello") + field(PHAS, "2") + field(TSE , "5") + field(DISA, "6") + field(DISV, "7") +} + +record(x, "recoverwrite") { +# now restore default values + field(DTYP, "") + field(DESC, "") + field(PHAS, "") + field(TSE , "") + field(TSEL, "") + field(DISA, "") + field(DISV, "") +} diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index ebaa44346..ede218cd5 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -376,6 +376,10 @@ long dbPutStringNum(DBENTRY *pdbentry, const char *pstring) if (!pfield) return S_dbLib_fieldNotFound; + /* empty string is the same as writing numeric zero */ + if(pstring[0]=='\0') + pstring = "0"; + switch (pflddes->field_type) { case DBF_CHAR: return epicsParseInt8(pstring, pfield, 0, NULL); From 99500b9be40a123d304ac017491048e5d61107cc Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 18 Sep 2016 17:35:19 -0400 Subject: [PATCH 13/25] dbStatic: more informative error for bad field value --- src/ioc/dbStatic/dbLexRoutines.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c index 12038a6ec..3ccece4d8 100644 --- a/src/ioc/dbStatic/dbLexRoutines.c +++ b/src/ioc/dbStatic/dbLexRoutines.c @@ -1060,10 +1060,12 @@ static void dbRecordField(char *name,char *value) dbTranslateEscape(value, value); /* yuck: in-place, but safe */ status = dbPutString(pdbentry,value); if(status) { - epicsPrintf("Can't set \"%s.%s\" to \"%s\"\n", - dbGetRecordName(pdbentry), name, value); - yyerror(NULL); - return; + char msg[128]; + errSymLookup(status, msg, sizeof(msg)); + epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s\n", + dbGetRecordName(pdbentry), name, value, msg); + yyerror(NULL); + return; } } From 5dcd3483badf71c0eec1b59f0d0adf53831f1dad Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 28 Feb 2017 00:25:43 -0600 Subject: [PATCH 14/25] dbStatic: dbPutStringNum() overflow handling Default to accepting over-size integers in DB fields, truncate to field size. E.g. permits setting DBF_LONG fields to 0xffffffff. Adds dbConvertStrict config variable to disable this. --- src/ioc/db/test/dbPutGetTest.c | 10 ++++ src/ioc/db/test/dbPutGetTest.db | 4 ++ src/ioc/dbStatic/dbStaticLib.h | 1 + src/ioc/dbStatic/dbStaticRun.c | 83 ++++++++++++++++++++++++++------- src/ioc/misc/dbCore.dbd | 1 + 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c index b9729940d..cd85b41d0 100644 --- a/src/ioc/db/test/dbPutGetTest.c +++ b/src/ioc/db/test/dbPutGetTest.c @@ -50,6 +50,14 @@ void testGetString(void) testdbGetStringEqual("recoverwrite.DISV", "0"); } +static +void testStringMax(void) +{ + testDiag("testStringMax()"); + + testdbGetStringEqual("recmax.DISA", "-1"); +} + void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); MAIN(dbPutGet) @@ -63,6 +71,8 @@ MAIN(dbPutGet) testGetString(); + testStringMax(); + testdbCleanup(); return testDone(); diff --git a/src/ioc/db/test/dbPutGetTest.db b/src/ioc/db/test/dbPutGetTest.db index 06a520c60..352d5aba7 100644 --- a/src/ioc/db/test/dbPutGetTest.db +++ b/src/ioc/db/test/dbPutGetTest.db @@ -29,3 +29,7 @@ record(x, "recoverwrite") { field(DISA, "") field(DISV, "") } + +record(x, "recmax") { + field(DISA, "0xffffffff") +} diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 1619a9090..4961e6236 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -244,6 +244,7 @@ epicsShareFunc void dbCatString(char **string, int *stringLength, char *pnew, char *separator); extern int dbStaticDebug; +extern int dbConvertStrict; #define S_dbLib_recordTypeNotFound (M_dbLib|1) /* Record Type does not exist */ #define S_dbLib_recExists (M_dbLib|3) /* Record Already exists */ diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index ede218cd5..236af771b 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -23,7 +23,7 @@ #include "epicsTypes.h" #include "errMdef.h" -#define epicsExportSharedSymbols +#include "epicsExport.h" /* #define epicsExportSharedSymbols */ #include "dbBase.h" #include "dbCommon.h" #include "dbStaticLib.h" @@ -31,6 +31,9 @@ #include "devSup.h" #include "special.h" +epicsShareDef int dbConvertStrict = 0; +epicsExportAddress(int, dbConvertStrict); + static long do_nothing(struct dbCommon *precord) { return 0; } /* Dummy DSXT used for soft device supports */ @@ -372,39 +375,85 @@ long dbPutStringNum(DBENTRY *pdbentry, const char *pstring) { dbFldDes *pflddes = pdbentry->pflddes; void *pfield = pdbentry->pfield; + long status; + epicsUInt64 u64; + epicsInt64 i64; if (!pfield) return S_dbLib_fieldNotFound; /* empty string is the same as writing numeric zero */ - if(pstring[0]=='\0') + if (pstring[0] == '\0') pstring = "0"; switch (pflddes->field_type) { case DBF_CHAR: - return epicsParseInt8(pstring, pfield, 0, NULL); - - case DBF_UCHAR: - return epicsParseUInt8(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt8(pstring, pfield, 0, NULL); + goto lax_signed; case DBF_SHORT: - return epicsParseInt16(pstring, pfield, 0, NULL); - - case DBF_USHORT: - case DBF_ENUM: - return epicsParseUInt16(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt16(pstring, pfield, 0, NULL); + goto lax_signed; case DBF_LONG: - return epicsParseInt32(pstring, pfield, 0, NULL); - - case DBF_ULONG: - return epicsParseUInt32(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt32(pstring, pfield, 0, NULL); + goto lax_signed; case DBF_INT64: - return epicsParseInt64(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt64(pstring, pfield, 0, NULL); + + lax_signed: + status = epicsParseInt64(pstring, &i64, 0, NULL); + if (status) + return status; + + switch (pflddes->field_type) { + case DBF_CHAR: *(epicsInt8 *)pfield = (epicsInt8) i64; break; + case DBF_SHORT: *(epicsInt16*)pfield = (epicsInt16)i64; break; + case DBF_LONG: *(epicsInt32*)pfield = (epicsInt32)i64; break; + case DBF_INT64: *(epicsInt64*)pfield = (epicsInt64)i64; break; + default: break; + } + return status; + + case DBF_UCHAR: + if (dbConvertStrict) + return epicsParseUInt8(pstring, pfield, 0, NULL); + goto lax_unsigned; + + case DBF_ENUM: + case DBF_USHORT: + if (dbConvertStrict) + return epicsParseUInt16(pstring, pfield, 0, NULL); + goto lax_unsigned; + + case DBF_ULONG: + if (dbConvertStrict) + return epicsParseUInt32(pstring, pfield, 0, NULL); + goto lax_unsigned; case DBF_UINT64: - return epicsParseUInt64(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseUInt64(pstring, pfield, 0, NULL); + + lax_unsigned: + status = epicsParseUInt64(pstring, &u64, 0, NULL); + if (status) + return status; + + switch (pflddes->field_type) { + case DBF_UCHAR: *(epicsUInt8 *)pfield = (epicsInt8) u64; break; + case DBF_ENUM: + case DBF_USHORT: *(epicsUInt16*)pfield = (epicsInt16)u64; break; + case DBF_ULONG: *(epicsUInt32*)pfield = (epicsInt32)u64; break; + case DBF_UINT64: *(epicsUInt64*)pfield = (epicsInt64)u64; break; + default: break; + } + return status; case DBF_FLOAT: return epicsParseFloat32(pstring, pfield, NULL); diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd index a2ce45806..7349994f7 100644 --- a/src/ioc/misc/dbCore.dbd +++ b/src/ioc/misc/dbCore.dbd @@ -14,6 +14,7 @@ variable(dbRecordsOnceOnly,int) variable(dbRecordsAbcSorted,int) variable(dbBptNotMonotonic,int) variable(dbQuietMacroWarnings,int) +variable(dbConvertStrict,int) # dbLoadTemplate settings variable(dbTemplateMaxVars,int) From b096dc3e01a2005301009e9eba69ac87de0b8a0d Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 28 Apr 2017 16:41:02 +0200 Subject: [PATCH 15/25] std/rec: add pod documentation for int64out record --- src/std/rec/{int64outRecord.dbd => int64outRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{int64outRecord.dbd => int64outRecord.dbd.pod} (100%) diff --git a/src/std/rec/int64outRecord.dbd b/src/std/rec/int64outRecord.dbd.pod similarity index 100% rename from src/std/rec/int64outRecord.dbd rename to src/std/rec/int64outRecord.dbd.pod From 1235ad76e78bd48a6a56c325bb2ee33150821750 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 2 May 2017 13:51:44 +0200 Subject: [PATCH 16/25] std/rec: add pod documentation content for int64out --- src/std/rec/int64outRecord.dbd.pod | 359 +++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) diff --git a/src/std/rec/int64outRecord.dbd.pod b/src/std/rec/int64outRecord.dbd.pod index fc088ed69..4abe969d2 100644 --- a/src/std/rec/int64outRecord.dbd.pod +++ b/src/std/rec/int64outRecord.dbd.pod @@ -6,7 +6,144 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=title Int64 (64bit Integer) Output Record (int64out) + +This record type is normally used to send an integer value of up to 64 bits +to an output device. +The record supports alarm, drive, graphics and control limits. + +=head2 Parameter Fields + +The record-specific fields are described below. + +=recordtype int64out + +=cut + recordtype(int64out) { + +=head3 Output Value Determination + +These fields control how the record determines the value to be output when it +gets processed: + +=fields OMSL, DOL, DRVH, DRVL, VAL + +The following steps are performed in order during record processing. + +=head4 Fetch Value + +The OMSL menu field is used to determine whether the DOL link field +should be used during processing or not: + +=over + +=item * +If OMSL is C the DOL link field is not used. +The new output value is taken from the VAL field, which may have been set from +elsewhere. + +=item * +If OMSL is C the DOL link field is read to obtain a value. + +=back + +=head4 Drive Limits + +The output value is now clipped to the range DRVL to DRVH inclusive, provided +that DRVH > DRVL. +The result is copied into the VAL field. + +=head3 Output Specification + +The int64 output record sends its desired output to the address in the +OUT field. For int64 outputs that write their values to devices, the +OUT field must specify the address of the I/O card. In addition, the +DTYP field must contain the name of the device support module. Be aware +that the address format differs according to the I/O bus used. See +Address Specification for information on the format of hardware +addresses. + +For soft records the output link can be a database link, a channel +access link, or a constant value. If the link is a constant, no output +is sent. See Address Specification for information on the format of +database and channel access addresses. + +=fields DTYP, OUT + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. +They display the value and other parameters of the analog output either +textually or graphically. + +EGU is a string of up to 16 characters describing the units that the +int64 output measures. It is retrieved by the get_units record support +routine. + +The HOPR and LOPR fields set the upper and lower display limits for the +VAL, HIHI, HIGH, LOW, and LOLO fields. +Both the get_graphic_double and get_control_double record support routines +retrieve these fields. If these values are defined, they must fulfill +LOPR E= HOPR. + +See Fields Common to All Record Types for more on the record name +(NAME) and description (DESC) fields. + +=fields EGU, HOPR, LOPR, NAME, DESC + +=head3 Alarm Parameters + +Possible alarm conditions for int64 outputs are UDF, SCAN, WRITE, +INVALID and limit alarms. The UDF, SCAN, WRITE, and INVALID alarms are +called by the record or device support routines. + +The limit alarms are configured by the user in the HIHI, LOLO, HIGH, +and LOW fields, which must be int64 values. For each of these +fields, there is a corresponding severity field which can be either +NO_ALARM, MINOR, MAJOR or INVALID. + +See Alarm Specification for a complete explanation of alarms and these +fields. See Invalid Alarm Output Action for more information on the +IVOA and IVOV fields. Alarm Fields lists other fields related to a +alarms that are common to all record types. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV + +=head3 Monitor Parameters + +These parameters are used to specify deadbands for monitors on the VAL +field. The monitors are sent when the value field exceeds the last +monitored field by the specified deadband. If these fields have a value +of zero, everytime the value changes, a monitor will be triggered; if +they have a value of -1, everytime the record is processed, monitors +are triggered. ADEL is the deadband for archive monitors, and MDEL the +deadband for all other types of monitors. See Monitor Specification for +a complete explanation of monitors. + +=fields ADEL, MDEL + +=head3 Run-time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the +int64 output. They are not configurable. They represent the current +state of the record. The record support routines use some of them for +more efficient processing. + +The LALM, MLST, and ALST fields are used to implement the hysteresis +factors for monitor callbacks. + +=fields LALM, ALST, MLST + +The following fields are used to operate the analog output in the +simulation mode. See Fields Common to Many Record Types for more +information on these fields. + +=fields SIOL, SIML, SIMM, SIMS + +=cut + include "dbCommon.dbd" field(VAL,DBF_INT64) { prompt("Desired Output") @@ -182,3 +319,225 @@ recordtype(int64out) { interest(2) } } + +=head2 Record Support + +=head3 Record Support Routines + +The following are the record support routines that would be of interest +to an application developer. Other routines are the C, +C, C, and C +routines. + +=over + +=item init_record + +This routine initializes SIMM if SIML is a constant or creates a +channel access link if SIML is PV_LINK. If SIOL is PV_LINK, a channel +access link is created. + +The routine next checks to see if the device support write routine is +defined. If either device support or the device support write routine +does not exist, an error message is issued and processing is +terminated. + +If DOL is a constant, then VAL is initialized with its value and UDF is +set to FALSE. + +If device support includes init_record, it is called. + +=item process + +See next section. + +=item get_alarm_double + +Sets the following values: + + upper_alarm_limit = HIHI + upper_warning_limit = HIGH + lower_warning_limit = LOW + lower_alarm_limit = LOLO + +=back + +=head3 Record Processing + +Routine C implements the following algorithm: + +=over + +=item 1. Check to see that the appropriate device support module +exists. If it doesn't, an error message is issued and processing is +terminated with the PACT field set to TRUE. This ensures that processes +will no longer be called for this record. Thus error storms will not +occur. + +=item 2. Check PACT. If PACT is FALSE, do the following: + +=over + +=item * Fetch value for closed loop mode: +if DOL is not a CONSTANT and OMSL is CLOSED_LOOP then get value from DOL. +In case of success, set UDF to FALSE. + +=item * Call convert: +if Drive limits are defined then force value to be within limits. + +=back + +=item 3. Check alarms: This routine checks to see if the new VAL causes +the alarm status and severity to change. If so, NSEV, NSTA and LALM are +set. It also honors the alarm hysteresis factor (HYST). Thus the value +must change by at least HYST before the alarm status and severity is +changed. + +=item 4. Check severity and write the new value. See Invalid Alarm +Output Action for details on how invalid alarms affect output records. + +=item 5. If PACT has been changed to TRUE, the device support write +output routine has started but has not completed writing the new value. +In this case, the processing routine merely returns, leaving PACT TRUE. + +=item 6. Check to see if monitors should be invoked: + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has +changed. + +=item * Archive and value change monitors are invoked if ADEL and MDEL +conditions are met. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 7. Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each analog output record must have an associated set of device support +routines. The primary responsibility of the device support routines is +to output a new value whenever write_ao is called. The device support +routines are primarily interested in the following fields: + +=over + +=item * +PACT E Process Active, used to indicate asynchronous completion + +=item * +DPVT E Device Private, reserved for device support to use + +=item * +OUT E Output Link, provides addressing information + +=back + +=head3 Device Support routines + +Device support consists of the following routines: + +=over + +=item C + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=item C + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=item C + +This optional routine is called by the record initialization code for each +int64out record instance that has its DTYP field set to use this device support. +It is normally used to check that the OUT address has the expected type and +points to a valid device; to allocate any record-specific buffer space and +other memory; and to connect any communication channels needed for the +C routine to work properly. + +=item C + +This optional routine is called whenever the record's SCAN field is being +changed to or from the value C to find out which I/O Interrupt Scan +list the record should be added to or deleted from. +If this routine is not provided, it will not be possible to set the SCAN field +to the value C at all. + +The C parameter is zero when the record is being added to the scan list, +and one when it is being removed from the list. +The routine must determine which interrupt source the record should be connected +to, which it indicates by the scan list that it points the location at C<*piosl> +to before returning. +It can prevent the SCAN field from being changed at all by returning a non-zero +value to its caller. + +In most cases the device support will create the I/O Interrupt Scan lists that +it returns for itself, by calling C once for +each separate interrupt source. +That API allocates memory and inializes the list, then passes back a pointer to +the new list in the location at C<*piosl>. +When the device support receives notification that the interrupt has occurred, +it announces that to the IOC by calling C +which will arrange for the appropriate records to be processed in a suitable +thread. +The C routine is safe to call from an interrupt service routine +on embedded architectures (vxWorks and RTEMS). + +=item C + +This essential routine is called whenever the record has a new output value to +send to the device. It is responsible for performing the write operation, using +the value found in the record's VAL field. +A return value of zero indicates success, any other value indicates that an +error occurred. + +This routine must not block (busy-wait) if the device takes more than a few +microseconds to accept the new value. In that case the routine must use +asynchronous completion to tell the record when the write operation eventually +completes. It signals that this is an asynchronous operation by setting the +record's PACT field to TRUE before it returns, having arranged for the record's +C routine to be called later once the write operation is over. When +that happens the C routine will be called again with PACT still +set to TRUE; it should then set it to FALSE to indicate the write has completed, +and return. + +=back + +=head2 Device Support For Soft Records + +Two soft device support modules Soft Channel and Soft Callback Channel are +provided for output records not related to actual hardware devices. The +OUT link type must be either a CONSTANT, DB_LINK, or CA_LINK. + +=head3 Soft Channel + +This module writes the current value using the record's VAL field. + +write_int64out calls C to write the current value. +See Soft Output for details. + +=head3 Soft Callback Channel + +This module is like the previous except that it writes the current value +using asynchronuous processing that will not finish until an asynchronuous +processing of the target record has finished. + +=cut From 93b47f103e1e5aa85621e48f08aeea0d0eab0231 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 3 May 2017 16:17:07 +0200 Subject: [PATCH 17/25] std/rec: add and improve pod for int64in and int64out --- src/std/rec/int64inRecord.dbd | 161 ------- src/std/rec/int64inRecord.dbd.pod | 528 +++++++++++++++++++++ src/std/rec/int64outRecord.dbd.pod | 731 ++++++++++++++++------------- 3 files changed, 920 insertions(+), 500 deletions(-) delete mode 100644 src/std/rec/int64inRecord.dbd create mode 100644 src/std/rec/int64inRecord.dbd.pod diff --git a/src/std/rec/int64inRecord.dbd b/src/std/rec/int64inRecord.dbd deleted file mode 100644 index b603c709e..000000000 --- a/src/std/rec/int64inRecord.dbd +++ /dev/null @@ -1,161 +0,0 @@ -#************************************************************************* -# Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -recordtype(int64in) { - include "dbCommon.dbd" - field(VAL,DBF_INT64) { - prompt("Current value") - promptgroup(GUI_INPUTS) - asl(ASL0) - pp(TRUE) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup(GUI_INPUTS) - interest(1) - } - field(EGU,DBF_STRING) { - prompt("Units name") - promptgroup(GUI_DISPLAY) - interest(1) - size(16) - prop(YES) - } - field(HOPR,DBF_INT64) { - prompt("High Operating Range") - promptgroup(GUI_DISPLAY) - interest(1) - prop(YES) - } - field(LOPR,DBF_INT64) { - prompt("Low Operating Range") - promptgroup(GUI_DISPLAY) - interest(1) - prop(YES) - } - field(HIHI,DBF_INT64) { - prompt("Hihi Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(LOLO,DBF_INT64) { - prompt("Lolo Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(HIGH,DBF_INT64) { - prompt("High Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(LOW,DBF_INT64) { - prompt("Low Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HYST,DBF_INT64) { - prompt("Alarm Deadband") - promptgroup(GUI_ALARMS) - interest(1) - } - field(AFTC, DBF_DOUBLE) { - prompt("Alarm Filter Time Constant") - promptgroup(GUI_ALARMS) - interest(1) - } - field(AFVL, DBF_DOUBLE) { - prompt("Alarm Filter Value") - special(SPC_NOMOD) - interest(3) - } - field(ADEL,DBF_INT64) { - prompt("Archive Deadband") - promptgroup(GUI_DISPLAY) - interest(1) - } - field(MDEL,DBF_INT64) { - prompt("Monitor Deadband") - promptgroup(GUI_DISPLAY) - interest(1) - } - field(LALM,DBF_INT64) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_INT64) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_INT64) { - prompt("Last Val Monitored") - special(SPC_NOMOD) - interest(3) - } - field(SIOL,DBF_INLINK) { - prompt("Sim Input Specifctn") - promptgroup(GUI_INPUTS) - interest(1) - } - field(SVAL,DBF_INT64) { - prompt("Simulation Value") - } - field(SIML,DBF_INLINK) { - prompt("Sim Mode Location") - promptgroup(GUI_INPUTS) - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Sim mode Alarm Svrty") - promptgroup(GUI_INPUTS) - interest(2) - menu(menuAlarmSevr) - } -} diff --git a/src/std/rec/int64inRecord.dbd.pod b/src/std/rec/int64inRecord.dbd.pod new file mode 100644 index 000000000..fb8cb3f71 --- /dev/null +++ b/src/std/rec/int64inRecord.dbd.pod @@ -0,0 +1,528 @@ +#************************************************************************* +# Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +=title 64bit Integer Input Record (int64in) + +This record type is normally used to obtain an integer value of up to 64 bits +from a hardware input. +The record supports alarm limits, alarm filtering, graphics and control +limits. + +=head2 Parameter Fields + +The record-specific fields are described below. + +=recordtype int64in + +=cut + +recordtype(int64in) { + +=head3 Input Specification + +These fields control where the record will read data from when it is processed: + +=fields DTYP, INP + +The DTYP field selects which device support layer should be responsible for +providing input data to the record. +The int64in device support layers provided by EPICS Base are documented in the +L section. +External support modules may provide additional device support for this record +type. +If not set explicitly, the DTYP value defaults to the first device support that +is loaded for the record type, which will usually be the C support +that comes with Base. + +The INP link field contains a database or channel access link or provides +hardware address information that the device support uses to determine where the +input data should come from. +The format for the INP field value depends on the device support layer that is +selected by the DTYP field. +See L

for a description of the various hardware +address formats supported. + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. +They do not affect the functioning of the record. + +=over + +=item * +DESC is a string that is usually used to briefly describe the record. + +=item * +EGU is a string of up to 16 characters naming the engineering units +that the VAL field represents. + +=item * +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +HIHI, HIGH, LOW, and LOLO fields. + +=back + +=fields DESC, EGU, HOPR, LOPR + +=head3 Alarm Limits + +The user configures limit alarms by putting numerical values into the HIHI, +HIGH, LOW and LOLO fields, and by setting the associated alarm severity in the +corresponding HHSV, HSV, LSV and LLSV menu fields. + +The HYST field controls hysteresis to prevent alarm chattering from an input +signal that is close to one of the limits and suffers from significant readout +noise. + +The AFTC field sets the time constant on a low-pass filter that delays the +reporting of limit alarms until the signal has been within the alarm range for +that number of seconds (the default AFTC value of zero retains the previous +behavior). + +The LALM field is used by the record at run-time to implement the alarm limit +functionality. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC, LALM + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the VAL +field. +The monitors are sent when the current value exceeds the last transmitted value +by the appropriate deadband. +If these fields are set to zero, a monitor will be triggered every time the +value changes; if set to -1, a monitor will be sent every time the record is +processed. + +The ADEL field sets the deadband for archive monitors (C events), while +the MDEL field controls value monitors (C events). + +The remaining fields are used by the record at run-time to implement the record +monitoring deadband functionality. + +=fields ADEL, MDEL, ALST, MLST + +=cut + + include "dbCommon.dbd" + field(VAL,DBF_INT64) { + prompt("Current value") + promptgroup(GUI_INPUTS) + asl(ASL0) + pp(TRUE) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup(GUI_INPUTS) + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Units name") + promptgroup(GUI_DISPLAY) + interest(1) + size(16) + prop(YES) + } + field(HOPR,DBF_INT64) { + prompt("High Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(LOPR,DBF_INT64) { + prompt("Low Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(HIHI,DBF_INT64) { + prompt("Hihi Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_INT64) { + prompt("Lolo Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_INT64) { + prompt("High Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_INT64) { + prompt("Low Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_INT64) { + prompt("Alarm Deadband") + promptgroup(GUI_ALARMS) + interest(1) + } + field(AFTC, DBF_DOUBLE) { + prompt("Alarm Filter Time Constant") + promptgroup(GUI_ALARMS) + interest(1) + } + field(AFVL, DBF_DOUBLE) { + prompt("Alarm Filter Value") + special(SPC_NOMOD) + interest(3) + } + field(ADEL,DBF_INT64) { + prompt("Archive Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(MDEL,DBF_INT64) { + prompt("Monitor Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(LALM,DBF_INT64) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_INT64) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_INT64) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + +=head3 Simulation Mode + +The record provides several fields to support simulation of absent hardware. +If the SIML field is set it is used to read a value into the SIMM field, which +controls whether simulation is used or not: + +=over + +=item * +SIMM must be zero (C) for the record to request a value from the device +support. + +=item * +If SIMM is C and the SIOL link field is set, a simulated value in +engineering units is read using the link into the SVAL field, from where it will +subsequently be copied into the VAL field. + +=back + +The SIMS field can be set to give the record an alarm severity while it is in +simulation mode. + +=fields SIML, SIMM, SIOL, SVAL, SIMS + +=cut + + field(SIOL,DBF_INLINK) { + prompt("Sim Input Specifctn") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SVAL,DBF_INT64) { + prompt("Simulation Value") + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup(GUI_INPUTS) + interest(2) + menu(menuAlarmSevr) + } +} + +=head2 Record Support + +=head3 Record Support Routines + +The following are the record support routines that would be of interest +to an application developer. +Other routines are the C, C, +C and C routines, which are used to +collect properties from the record for the complex DBR data structures. + +=head4 init_record + +This routine first initializes the simulation mode mechanism by setting SIMM +if SIML is a constant, and setting SVAL if SIOL is a constant. + +It then checks if the device support and the device support's +C routine are defined. +If either one does not exist, an error message is issued +and processing is terminated. + +If device support includes C, it is called. + +Finally, the deadband mechanisms for monitors and level alarms are +initialized. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine C implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module and its +C routine are defined. +If either one does not exist, an error message is issued and processing is +terminated with the PACT field set to TRUE, effectively blocking the record +to avoid error storms. + +=item 2. + +Determine the value: + +If PACT is TRUE, call the device support C routine and return. + +If PACT is FALSE, read the value, honoring simulation mode: + +=over + +=item * Get SIMM by reading the SIML link. + +=item * If SIMM is C, +call the device support C routine and return. + +=item * If SIMM is C, +read the simulated value into SVAL using the SIOL link, +then copy the value into VAL and set UDF to 0 on success. + +=item * Raise an alarm for other values of SIMM. + +=item * Set the record to the severity configured in SIMS. + +=back + +=item 3. + +If PACT has been changed to TRUE, the device support signals asynchronous +processing: its C output routine has started, but not +completed reading the new value. +In this case, the processing routine merely returns, leaving PACT TRUE. + +=item 4. + +Set PACT to TRUE. Get the processing time stamp. Set UDF to 0 if reading +the value was successful. + +=item 5. + +Check UDF and level alarms: This routine checks to see if the record is +undefined (UDF is TRUE) or if the new VAL causes the alarm status +and severity to change. In the latter case, NSEV, NSTA and LALM are set. +It also honors the alarm hysteresis factor (HYST): the value must change +by at least HYST between level alarm status and severity changes. +If AFTC is set, alarm level filtering is applied. + +=item 6. + +Check to see if monitors should be invoked: + +=over + +=item * Alarm monitors are posted if the alarm status or severity have +changed. + +=item * Archive and value change monitors are posted if ADEL and MDEL +conditions (see L) are met. + +=back + +=item 7. + +Scan (process) forward link if necessary, set PACT to FALSE, and return. + +=back + +=head2 Device Support + +=head3 Device Support Interface + +The record requires device support to provide an entry table (dset) which +defines the following members: + + typedef struct { + long number; + long (*report)(int level); + long (*init)(int after); + long (*init_record)(int64inRecord *prec); + long (*get_ioint_info)(int cmd, int64inRecord *prec, IOSCANPVT *piosl); + long (*read_int64in)(int64inRecord *prec); + } int64indset; + +The module must set C to at least 5, and provide a pointer to its +C routine; the other function pointers may be C if their +associated functionality is not required for this support layer. +Most device supports also provide an C routine to configure the +record instance and connect it to the hardware or driver support layer. + +The individual routines are described below. + +=head3 Device Support Routines + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 long init_record(int64inRecord *prec) + +This optional routine is called by the record initialization code for each +int64in record instance that has its DTYP field set to use this device support. +It is normally used to check that the INP address is the expected type and that +it points to a valid device; to allocate any record-specific buffer space and +other memory; and to connect any communication channels needed for the +C routine to work properly. + +=head4 long get_ioint_info(int cmd, int64inRecord *prec, IOSCANPVT *piosl) + +This optional routine is called whenever the record's SCAN field is being +changed to or from the value C to find out which I/O Interrupt Scan +list the record should be added to or deleted from. +If this routine is not provided, it will not be possible to set the SCAN field +to the value C at all. + +The C parameter is zero when the record is being added to the scan list, +and one when it is being removed from the list. +The routine must determine which interrupt source the record should be connected +to, which it indicates by the scan list that it points the location at C<*piosl> +to before returning. +It can prevent the SCAN field from being changed at all by returning a non-zero +value to its caller. + +In most cases the device support will create the I/O Interrupt Scan lists that +it returns for itself, by calling C once for +each separate interrupt source. +That routine allocates memory and inializes the list, then passes back a pointer +to the new list in the location at C<*piosl>. + +When the device support receives notification that the interrupt has occurred, +it announces that to the IOC by calling C +which will arrange for the appropriate records to be processed in a suitable +thread. +The C routine is safe to call from an interrupt service routine +on embedded architectures (vxWorks and RTEMS). + +=head4 long read_int64in(int64inRecord *prec) + +This essential routine is called when the record wants a new value from the +addressed device. +It is responsible for performing (or at least initiating) a read operation, and +(eventually) returning its value to the record. + +If the device may take more than a few microseconds to return the new value, +this routine must never block (busy-wait), but use the asynchronous +processing mechanism. +In that case it signals the asynchronous operation by setting the record's +PACT field to TRUE before it returns, having arranged for the record's +C routine to be called later once the read operation is finished. +When that happens, the C routine will be called again with +PACT still set to TRUE; it should then set it to FALSE to indicate the read +has completed, and return. + +A return value of zero indicates success, any other value indicates that an +error occurred. + +=head3 Extended Device Support + +... + +=cut + +=head2 Device Support For Soft Records + +Two soft device support modules, Soft Channel and Soft Callback Channel, are +provided for input records not related to actual hardware devices. The +INP link type must be either a CONSTANT, DB_LINK, or CA_LINK. + +=head3 Soft Channel + +This module reads the value using the record's INP link. + +C calls C to read the value. + +=head3 Soft Callback Channel + +This module is like the previous except that it reads the value +using asynchronous processing that will not complete until an asynchronous +processing of the INP target record has completed. + +=cut diff --git a/src/std/rec/int64outRecord.dbd.pod b/src/std/rec/int64outRecord.dbd.pod index 4abe969d2..4903d2da4 100644 --- a/src/std/rec/int64outRecord.dbd.pod +++ b/src/std/rec/int64outRecord.dbd.pod @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=title Int64 (64bit Integer) Output Record (int64out) +=title 64bit Integer Output Record (int64out) This record type is normally used to send an integer value of up to 64 bits to an output device. @@ -45,279 +45,323 @@ The new output value is taken from the VAL field, which may have been set from elsewhere. =item * -If OMSL is C the DOL link field is read to obtain a value. +If OMSL is C the DOL link field is used to obtain a value. =back =head4 Drive Limits -The output value is now clipped to the range DRVL to DRVH inclusive, provided +The output value is clipped to the range DRVL to DRVH inclusive, provided that DRVH > DRVL. The result is copied into the VAL field. =head3 Output Specification -The int64 output record sends its desired output to the address in the -OUT field. For int64 outputs that write their values to devices, the -OUT field must specify the address of the I/O card. In addition, the -DTYP field must contain the name of the device support module. Be aware -that the address format differs according to the I/O bus used. See -Address Specification for information on the format of hardware -addresses. - -For soft records the output link can be a database link, a channel -access link, or a constant value. If the link is a constant, no output -is sent. See Address Specification for information on the format of -database and channel access addresses. +These fields control where the record will read data from when it is processed: =fields DTYP, OUT +The DTYP field selects which device support layer should be responsible for +writing output data. +The int64out device support layers provided by EPICS Base are documented in the +L section. +External support modules may provide additional device support for this record +type. +If not set explicitly, the DTYP value defaults to the first device support that +is loaded for the record type, which will usually be the C support +that comes with Base. + +The OUT link field contains a database or channel access link or provides +hardware address information that the device support uses to determine where the +output data should be sent to. +The format for the OUT field value depends on the device support layer that is +selected by the DTYP field. +See L
for a description of the various hardware +address formats supported. + =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator. -They display the value and other parameters of the analog output either -textually or graphically. +They do not affect the functioning of the record. -EGU is a string of up to 16 characters describing the units that the -int64 output measures. It is retrieved by the get_units record support -routine. +=over -The HOPR and LOPR fields set the upper and lower display limits for the -VAL, HIHI, HIGH, LOW, and LOLO fields. -Both the get_graphic_double and get_control_double record support routines -retrieve these fields. If these values are defined, they must fulfill -LOPR E= HOPR. +=item * +DESC is a string that is usually used to briefly describe the record. -See Fields Common to All Record Types for more on the record name -(NAME) and description (DESC) fields. +=item * +EGU is a string of up to 16 characters naming the engineering units +that the VAL field represents. -=fields EGU, HOPR, LOPR, NAME, DESC +=item * +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +HIHI, HIGH, LOW, and LOLO fields. -=head3 Alarm Parameters +=back -Possible alarm conditions for int64 outputs are UDF, SCAN, WRITE, -INVALID and limit alarms. The UDF, SCAN, WRITE, and INVALID alarms are -called by the record or device support routines. +=fields DESC, EGU, HOPR, LOPR -The limit alarms are configured by the user in the HIHI, LOLO, HIGH, -and LOW fields, which must be int64 values. For each of these -fields, there is a corresponding severity field which can be either -NO_ALARM, MINOR, MAJOR or INVALID. +=head3 Alarm Limits -See Alarm Specification for a complete explanation of alarms and these -fields. See Invalid Alarm Output Action for more information on the -IVOA and IVOV fields. Alarm Fields lists other fields related to a -alarms that are common to all record types. +The user configures limit alarms by putting numerical values into the HIHI, +HIGH, LOW and LOLO fields, and by setting the associated alarm severities +in the corresponding HHSV, HSV, LSV and LLSV menu fields. -=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV +The HYST field controls hysteresis to prevent alarm chattering from an input +signal that is close to one of the limits and suffers from significant readout +noise. + +The LALM field is used by the record at run-time to implement the alarm limit +hysteresis functionality. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, LALM =head3 Monitor Parameters -These parameters are used to specify deadbands for monitors on the VAL -field. The monitors are sent when the value field exceeds the last -monitored field by the specified deadband. If these fields have a value -of zero, everytime the value changes, a monitor will be triggered; if -they have a value of -1, everytime the record is processed, monitors -are triggered. ADEL is the deadband for archive monitors, and MDEL the -deadband for all other types of monitors. See Monitor Specification for -a complete explanation of monitors. +These parameters are used to determine when to send monitors placed on the VAL +field. +The monitors are sent when the current value exceeds the last transmitted value +by the appropriate deadband. +If these fields are set to zero, a monitor will be triggered every time the +value changes; if set to -1, a monitor will be sent every time the record is +processed. -=fields ADEL, MDEL +The ADEL field sets the deadband for archive monitors (C events), while +the MDEL field controls value monitors (C events). -=head3 Run-time and Simulation Mode Parameters +The remaining fields are used by the record at run-time to implement the record +monitoring deadband functionality. -These parameters are used by the run-time code for processing the -int64 output. They are not configurable. They represent the current -state of the record. The record support routines use some of them for -more efficient processing. - -The LALM, MLST, and ALST fields are used to implement the hysteresis -factors for monitor callbacks. - -=fields LALM, ALST, MLST - -The following fields are used to operate the analog output in the -simulation mode. See Fields Common to Many Record Types for more -information on these fields. - -=fields SIOL, SIML, SIMM, SIMS +=fields ADEL, MDEL, ALST, MLST =cut - include "dbCommon.dbd" - field(VAL,DBF_INT64) { - prompt("Desired Output") - promptgroup(GUI_OUTPUT) - asl(ASL0) - pp(TRUE) - } - field(OUT,DBF_OUTLINK) { - prompt("Output Specification") - promptgroup(GUI_OUTPUT) - interest(1) - } - field(DOL,DBF_INLINK) { - prompt("Desired Output Loc") - promptgroup(GUI_OUTPUT) - interest(1) - } - field(OMSL,DBF_MENU) { - prompt("Output Mode Select") - promptgroup(GUI_OUTPUT) - interest(1) - menu(menuOmsl) - } - field(EGU,DBF_STRING) { - prompt("Units name") - promptgroup(GUI_DISPLAY) - interest(1) - size(16) - prop(YES) - } - field(DRVH,DBF_INT64) { - prompt("Drive High Limit") - promptgroup(GUI_OUTPUT) - pp(TRUE) - interest(1) - prop(YES) - } - field(DRVL,DBF_INT64) { - prompt("Drive Low Limit") - promptgroup(GUI_OUTPUT) - pp(TRUE) - interest(1) - prop(YES) - } - field(HOPR,DBF_INT64) { - prompt("High Operating Range") - promptgroup(GUI_DISPLAY) - interest(1) - prop(YES) - } - field(LOPR,DBF_INT64) { - prompt("Low Operating Range") - promptgroup(GUI_DISPLAY) - interest(1) - prop(YES) - } - field(HIHI,DBF_INT64) { - prompt("Hihi Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(LOLO,DBF_INT64) { - prompt("Lolo Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(HIGH,DBF_INT64) { - prompt("High Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(LOW,DBF_INT64) { - prompt("Low Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - prop(YES) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) - menu(menuAlarmSevr) - } - field(HYST,DBF_INT64) { - prompt("Alarm Deadband") - promptgroup(GUI_ALARMS) - interest(1) - } - field(ADEL,DBF_INT64) { - prompt("Archive Deadband") - promptgroup(GUI_DISPLAY) - interest(1) - } - field(MDEL,DBF_INT64) { - prompt("Monitor Deadband") - promptgroup(GUI_DISPLAY) - interest(1) - } - field(LALM,DBF_INT64) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_INT64) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_INT64) { - prompt("Last Val Monitored") - special(SPC_NOMOD) - interest(3) - } - field(SIOL,DBF_OUTLINK) { - prompt("Sim Output Specifctn") - promptgroup(GUI_INPUTS) - interest(1) - } - field(SIML,DBF_INLINK) { - prompt("Sim Mode Location") - promptgroup(GUI_INPUTS) - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - interest(1) - menu(menuYesNo) - } - field(SIMS,DBF_MENU) { - prompt("Sim mode Alarm Svrty") - promptgroup(GUI_INPUTS) - interest(2) - menu(menuAlarmSevr) - } - field(IVOA,DBF_MENU) { - prompt("INVALID output action") - promptgroup(GUI_OUTPUT) - interest(2) - menu(menuIvoa) - } - field(IVOV,DBF_INT64) { - prompt("INVALID output value") - promptgroup(GUI_OUTPUT) - interest(2) - } + include "dbCommon.dbd" + field(VAL,DBF_INT64) { + prompt("Desired Output") + promptgroup(GUI_OUTPUT) + asl(ASL0) + pp(TRUE) + } + field(OUT,DBF_OUTLINK) { + prompt("Output Specification") + promptgroup(GUI_OUTPUT) + interest(1) + } + field(DOL,DBF_INLINK) { + prompt("Desired Output Loc") + promptgroup(GUI_OUTPUT) + interest(1) + } + field(OMSL,DBF_MENU) { + prompt("Output Mode Select") + promptgroup(GUI_OUTPUT) + interest(1) + menu(menuOmsl) + } + field(EGU,DBF_STRING) { + prompt("Units name") + promptgroup(GUI_DISPLAY) + interest(1) + size(16) + prop(YES) + } + field(DRVH,DBF_INT64) { + prompt("Drive High Limit") + promptgroup(GUI_OUTPUT) + pp(TRUE) + interest(1) + prop(YES) + } + field(DRVL,DBF_INT64) { + prompt("Drive Low Limit") + promptgroup(GUI_OUTPUT) + pp(TRUE) + interest(1) + prop(YES) + } + field(HOPR,DBF_INT64) { + prompt("High Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(LOPR,DBF_INT64) { + prompt("Low Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) + prop(YES) + } + field(HIHI,DBF_INT64) { + prompt("Hihi Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOLO,DBF_INT64) { + prompt("Lolo Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HIGH,DBF_INT64) { + prompt("High Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(LOW,DBF_INT64) { + prompt("Low Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + prop(YES) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) + menu(menuAlarmSevr) + } + field(HYST,DBF_INT64) { + prompt("Alarm Deadband") + promptgroup(GUI_ALARMS) + interest(1) + } + field(ADEL,DBF_INT64) { + prompt("Archive Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(MDEL,DBF_INT64) { + prompt("Monitor Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(LALM,DBF_INT64) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_INT64) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_INT64) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + +=head3 Simulation Mode + +The record provides several fields to support simulation of absent hardware. +If the SIML field is set it is used to read a value into the SIMM field, +which controls whether simulation is used or not: + +=over + +=item * +SIMM must be zero (C) for the record to write a value to the device +support. + +=item * +If SIMM is C and the SIOL link field is set, the value in engineering +units is written using the link. + +=back + +The SIMS field can be set to give the record an alarm severity while it is in +simulation mode. + +=fields SIML, SIMM, SIOL, SIMS + +=cut + + field(SIOL,DBF_OUTLINK) { + prompt("Sim Output Specifctn") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIML,DBF_INLINK) { + prompt("Sim Mode Location") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + interest(1) + menu(menuYesNo) + } + field(SIMS,DBF_MENU) { + prompt("Sim mode Alarm Svrty") + promptgroup(GUI_INPUTS) + interest(2) + menu(menuAlarmSevr) + } + +=head3 Invalid Alarm Output Action + +Whenever an output record is put into INVALID alarm severity, IVOA specifies +the action to take. + +=over + +=item C (default) + +Write the value. Same as if severity is lower than INVALID. + +=item C + +Do not write value. + +=item C + +Set VAL to IVOV, then write the value. + +=back + +=fields IVOA, IVOV + +=cut + + field(IVOA,DBF_MENU) { + prompt("INVALID output action") + promptgroup(GUI_OUTPUT) + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_INT64) { + prompt("INVALID output value") + promptgroup(GUI_OUTPUT) + interest(2) + } } =head2 Record Support @@ -325,128 +369,131 @@ information on these fields. =head3 Record Support Routines The following are the record support routines that would be of interest -to an application developer. Other routines are the C, -C, C, and C -routines. +to an application developer. +Other routines are the C, C, +C and C routines, which are used to +collect properties from the record for the complex DBR data structures. -=over +=head4 init_record -=item init_record +This routine first initializes the simulation mode mechanism by setting SIMM +if SIML is a constant. -This routine initializes SIMM if SIML is a constant or creates a -channel access link if SIML is PV_LINK. If SIOL is PV_LINK, a channel -access link is created. - -The routine next checks to see if the device support write routine is -defined. If either device support or the device support write routine -does not exist, an error message is issued and processing is -terminated. +It then checks if the device support and the device support's +C routine are defined. +If either one does not exist, an error message is issued +and processing is terminated. If DOL is a constant, then VAL is initialized with its value and UDF is set to FALSE. -If device support includes init_record, it is called. +If device support includes C, it is called. -=item process +Finally, the deadband mechanisms for monitors and level alarms are +initialized. + +=head4 process See next section. -=item get_alarm_double - -Sets the following values: - - upper_alarm_limit = HIHI - upper_warning_limit = HIGH - lower_warning_limit = LOW - lower_alarm_limit = LOLO - -=back - =head3 Record Processing Routine C implements the following algorithm: =over -=item 1. Check to see that the appropriate device support module -exists. If it doesn't, an error message is issued and processing is -terminated with the PACT field set to TRUE. This ensures that processes -will no longer be called for this record. Thus error storms will not -occur. +=item 1. -=item 2. Check PACT. If PACT is FALSE, do the following: +Check to see that the appropriate device support module and its +C routine are defined. +If either one does not exist, an error message is issued and processing is +terminated with the PACT field set to TRUE, effectively blocking the record +to avoid error storms. + +=item 2. + +Check PACT. If PACT is FALSE, do the following: =over -=item * Fetch value for closed loop mode: -if DOL is not a CONSTANT and OMSL is CLOSED_LOOP then get value from DOL. -In case of success, set UDF to FALSE. +=item * Determine value, honoring closed loop mode: +if DOL is not a CONSTANT and OMSL is CLOSED_LOOP then get value from DOL +setting UDF to FALSE in case of success, else use the VAL field. -=item * Call convert: -if Drive limits are defined then force value to be within limits. +=item * Call C: +if drive limits are defined then force value to be within those limits. =back -=item 3. Check alarms: This routine checks to see if the new VAL causes -the alarm status and severity to change. If so, NSEV, NSTA and LALM are -set. It also honors the alarm hysteresis factor (HYST). Thus the value -must change by at least HYST before the alarm status and severity is -changed. +=item 3. -=item 4. Check severity and write the new value. See Invalid Alarm -Output Action for details on how invalid alarms affect output records. +Check UDF and level alarms: This routine checks to see if the record is +undefined (UDF is TRUE) or if the new VAL causes the alarm status +and severity to change. In the latter case, NSEV, NSTA and LALM are set. +It also honors the alarm hysteresis factor (HYST): the value must change +by at least HYST between level alarm status and severity changes. -=item 5. If PACT has been changed to TRUE, the device support write -output routine has started but has not completed writing the new value. +=item 4. + +Check severity and write the new value. See L +for details on how invalid alarms affect output records. + +=item 5. + +If PACT has been changed to TRUE, the device support signals asynchronous +processing: its C output routine has started, but not +completed writing the new value. In this case, the processing routine merely returns, leaving PACT TRUE. -=item 6. Check to see if monitors should be invoked: +=item 6. + +Check to see if monitors should be invoked: =over -=item * Alarm monitors are invoked if the alarm status or severity has +=item * Alarm monitors are posted if the alarm status or severity have changed. -=item * Archive and value change monitors are invoked if ADEL and MDEL -conditions are met. +=item * Archive and value change monitors are posted if ADEL and MDEL +conditions (see L) are met. =item * NSEV and NSTA are reset to 0. =back -=item 7. Scan forward link if necessary, set PACT FALSE, and return. +=item 7. + +Scan (process) forward link if necessary, set PACT to FALSE, and return. =back =head2 Device Support -=head3 Fields Of Interest To Device Support +=head3 Device Support Interface -Each analog output record must have an associated set of device support -routines. The primary responsibility of the device support routines is -to output a new value whenever write_ao is called. The device support -routines are primarily interested in the following fields: +The record requires device support to provide an entry table (dset) which +defines the following members: -=over + typedef struct { + long number; + long (*report)(int level); + long (*init)(int after); + long (*init_record)(int64outRecord *prec); + long (*get_ioint_info)(int cmd, int64outRecord *prec, IOSCANPVT *piosl); + long (*write_int64out)(int64outRecord *prec); + } int64outdset; -=item * -PACT E Process Active, used to indicate asynchronous completion +The module must set C to at least 5, and provide a pointer to its +C routine; the other function pointers may be C if their +associated functionality is not required for this support layer. +Most device supports also provide an C routine to configure the +record instance and connect it to the hardware or driver support layer. -=item * -DPVT E Device Private, reserved for device support to use +The individual routines are described below. -=item * -OUT E Output Link, provides addressing information +=head3 Device Support Routines -=back - -=head3 Device Support routines - -Device support consists of the following routines: - -=over - -=item C +=head4 long report(int level) This optional routine is called by the IOC command C and is passed the report level that was requested by the user. @@ -456,7 +503,7 @@ information at higher levels, or to select different types of information with different levels. Level zero should print no more than a small summary. -=item C +=head4 long init(int after) This optional routine is called twice at IOC initialization time. The first call happens before any of the C calls are made, with @@ -464,16 +511,16 @@ the integer parameter C set to 0. The second call happens after all of the C calls have been made, with C set to 1. -=item C +=head4 long init_record(int64outRecord *prec) This optional routine is called by the record initialization code for each int64out record instance that has its DTYP field set to use this device support. -It is normally used to check that the OUT address has the expected type and -points to a valid device; to allocate any record-specific buffer space and -other memory; and to connect any communication channels needed for the +It is normally used to check that the OUT address is the expected type and that +it points to a valid device, to allocate any record-specific buffer space and +other memory, and to connect any communication channels needed for the C routine to work properly. -=item C +=head4 long get_ioint_info(int cmd, int64outRecord *prec, IOSCANPVT *piosl) This optional routine is called whenever the record's SCAN field is being changed to or from the value C to find out which I/O Interrupt Scan @@ -492,8 +539,9 @@ value to its caller. In most cases the device support will create the I/O Interrupt Scan lists that it returns for itself, by calling C once for each separate interrupt source. -That API allocates memory and inializes the list, then passes back a pointer to -the new list in the location at C<*piosl>. +That routine allocates memory and inializes the list, then passes back a pointer +to the new list in the location at C<*piosl>. + When the device support receives notification that the interrupt has occurred, it announces that to the IOC by calling C which will arrange for the appropriate records to be processed in a suitable @@ -501,29 +549,35 @@ thread. The C routine is safe to call from an interrupt service routine on embedded architectures (vxWorks and RTEMS). -=item C +=head4 long write_int64out(int64outRecord *prec) + +This essential routine is called when the record wants to write a new value +to the addressed device. +It is responsible for performing (or at least initiating) a write operation, +using the value from the record's VAL field. + +If the device may take more than a few microseconds to accept the new value, +this routine must never block (busy-wait), but use the asynchronous +processing mechanism. +In that case it signals the asynchronous operation by setting the record's +PACT field to TRUE before it returns, having arranged for the record's +C routine to be called later once the write operation is over. +When that happens, the C routine will be called again with +PACT still set to TRUE; it should then set it to FALSE to indicate the write +has completed, and return. -This essential routine is called whenever the record has a new output value to -send to the device. It is responsible for performing the write operation, using -the value found in the record's VAL field. A return value of zero indicates success, any other value indicates that an error occurred. -This routine must not block (busy-wait) if the device takes more than a few -microseconds to accept the new value. In that case the routine must use -asynchronous completion to tell the record when the write operation eventually -completes. It signals that this is an asynchronous operation by setting the -record's PACT field to TRUE before it returns, having arranged for the record's -C routine to be called later once the write operation is over. When -that happens the C routine will be called again with PACT still -set to TRUE; it should then set it to FALSE to indicate the write has completed, -and return. +=head3 Extended Device Support -=back +... + +=cut =head2 Device Support For Soft Records -Two soft device support modules Soft Channel and Soft Callback Channel are +Two soft device support modules, Soft Channel and Soft Callback Channel, are provided for output records not related to actual hardware devices. The OUT link type must be either a CONSTANT, DB_LINK, or CA_LINK. @@ -531,13 +585,12 @@ OUT link type must be either a CONSTANT, DB_LINK, or CA_LINK. This module writes the current value using the record's VAL field. -write_int64out calls C to write the current value. -See Soft Output for details. +C calls C to write the current value. =head3 Soft Callback Channel This module is like the previous except that it writes the current value -using asynchronuous processing that will not finish until an asynchronuous -processing of the target record has finished. +using asynchronous processing that will not complete until an asynchronous +processing of the target record has completed. =cut From 5761028d6f19274842a0980a32bff48aba0878f4 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 3 May 2017 17:00:19 +0200 Subject: [PATCH 18/25] std/rec: fix promptgroups in dbd.pod files --- src/std/rec/compressRecord.dbd.pod | 2 +- src/std/rec/int64inRecord.dbd.pod | 40 ++++++++++++------------ src/std/rec/int64outRecord.dbd.pod | 50 +++++++++++++++--------------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index c1cb8cc29..265cdfe8a 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -97,7 +97,7 @@ recordtype(compress) { } field(BALG,DBF_MENU) { prompt("Buffering Algorithm") - promptgroup(GUI_ALARMS) + promptgroup("30 - Action") special(SPC_RESET) interest(1) menu(bufferingALG) diff --git a/src/std/rec/int64inRecord.dbd.pod b/src/std/rec/int64inRecord.dbd.pod index fb8cb3f71..919c3d559 100644 --- a/src/std/rec/int64inRecord.dbd.pod +++ b/src/std/rec/int64inRecord.dbd.pod @@ -113,98 +113,98 @@ monitoring deadband functionality. include "dbCommon.dbd" field(VAL,DBF_INT64) { prompt("Current value") - promptgroup(GUI_INPUTS) + promptgroup("40 - Input") asl(ASL0) pp(TRUE) } field(INP,DBF_INLINK) { prompt("Input Specification") - promptgroup(GUI_INPUTS) + promptgroup("40 - Input") interest(1) } field(EGU,DBF_STRING) { prompt("Units name") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) size(16) prop(YES) } field(HOPR,DBF_INT64) { prompt("High Operating Range") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) prop(YES) } field(LOPR,DBF_INT64) { prompt("Low Operating Range") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) prop(YES) } field(HIHI,DBF_INT64) { prompt("Hihi Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(LOLO,DBF_INT64) { prompt("Lolo Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(HIGH,DBF_INT64) { prompt("High Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(LOW,DBF_INT64) { prompt("Low Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(HHSV,DBF_MENU) { prompt("Hihi Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(LLSV,DBF_MENU) { prompt("Lolo Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(HSV,DBF_MENU) { prompt("High Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(LSV,DBF_MENU) { prompt("Low Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(HYST,DBF_INT64) { prompt("Alarm Deadband") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") interest(1) } field(AFTC, DBF_DOUBLE) { prompt("Alarm Filter Time Constant") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") interest(1) } field(AFVL, DBF_DOUBLE) { @@ -214,12 +214,12 @@ monitoring deadband functionality. } field(ADEL,DBF_INT64) { prompt("Archive Deadband") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) } field(MDEL,DBF_INT64) { prompt("Monitor Deadband") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) } field(LALM,DBF_INT64) { @@ -266,7 +266,7 @@ simulation mode. field(SIOL,DBF_INLINK) { prompt("Sim Input Specifctn") - promptgroup(GUI_INPUTS) + promptgroup("90 - Simulate") interest(1) } field(SVAL,DBF_INT64) { @@ -274,7 +274,7 @@ simulation mode. } field(SIML,DBF_INLINK) { prompt("Sim Mode Location") - promptgroup(GUI_INPUTS) + promptgroup("90 - Simulate") interest(1) } field(SIMM,DBF_MENU) { @@ -284,7 +284,7 @@ simulation mode. } field(SIMS,DBF_MENU) { prompt("Sim mode Alarm Svrty") - promptgroup(GUI_INPUTS) + promptgroup("90 - Simulate") interest(2) menu(menuAlarmSevr) } diff --git a/src/std/rec/int64outRecord.dbd.pod b/src/std/rec/int64outRecord.dbd.pod index 4903d2da4..b489ada97 100644 --- a/src/std/rec/int64outRecord.dbd.pod +++ b/src/std/rec/int64outRecord.dbd.pod @@ -139,128 +139,128 @@ monitoring deadband functionality. include "dbCommon.dbd" field(VAL,DBF_INT64) { prompt("Desired Output") - promptgroup(GUI_OUTPUT) + promptgroup("50 - Output") asl(ASL0) pp(TRUE) } field(OUT,DBF_OUTLINK) { prompt("Output Specification") - promptgroup(GUI_OUTPUT) + promptgroup("50 - Output") interest(1) } field(DOL,DBF_INLINK) { prompt("Desired Output Loc") - promptgroup(GUI_OUTPUT) + promptgroup("40 - Input") interest(1) } field(OMSL,DBF_MENU) { prompt("Output Mode Select") - promptgroup(GUI_OUTPUT) + promptgroup("50 - Output") interest(1) menu(menuOmsl) } field(EGU,DBF_STRING) { prompt("Units name") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) size(16) prop(YES) } field(DRVH,DBF_INT64) { prompt("Drive High Limit") - promptgroup(GUI_OUTPUT) + promptgroup("30 - Action") pp(TRUE) interest(1) prop(YES) } field(DRVL,DBF_INT64) { prompt("Drive Low Limit") - promptgroup(GUI_OUTPUT) + promptgroup("30 - Action") pp(TRUE) interest(1) prop(YES) } field(HOPR,DBF_INT64) { prompt("High Operating Range") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) prop(YES) } field(LOPR,DBF_INT64) { prompt("Low Operating Range") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) prop(YES) } field(HIHI,DBF_INT64) { prompt("Hihi Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(LOLO,DBF_INT64) { prompt("Lolo Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(HIGH,DBF_INT64) { prompt("High Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(LOW,DBF_INT64) { prompt("Low Alarm Limit") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) prop(YES) } field(HHSV,DBF_MENU) { prompt("Hihi Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(LLSV,DBF_MENU) { prompt("Lolo Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(HSV,DBF_MENU) { prompt("High Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(LSV,DBF_MENU) { prompt("Low Severity") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") pp(TRUE) interest(1) menu(menuAlarmSevr) } field(HYST,DBF_INT64) { prompt("Alarm Deadband") - promptgroup(GUI_ALARMS) + promptgroup("70 - Alarm") interest(1) } field(ADEL,DBF_INT64) { prompt("Archive Deadband") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) } field(MDEL,DBF_INT64) { prompt("Monitor Deadband") - promptgroup(GUI_DISPLAY) + promptgroup("80 - Display") interest(1) } field(LALM,DBF_INT64) { @@ -306,12 +306,12 @@ simulation mode. field(SIOL,DBF_OUTLINK) { prompt("Sim Output Specifctn") - promptgroup(GUI_INPUTS) + promptgroup("90 - Simulate") interest(1) } field(SIML,DBF_INLINK) { prompt("Sim Mode Location") - promptgroup(GUI_INPUTS) + promptgroup("90 - Simulate") interest(1) } field(SIMM,DBF_MENU) { @@ -321,7 +321,7 @@ simulation mode. } field(SIMS,DBF_MENU) { prompt("Sim mode Alarm Svrty") - promptgroup(GUI_INPUTS) + promptgroup("90 - Simulate") interest(2) menu(menuAlarmSevr) } @@ -353,13 +353,13 @@ Set VAL to IVOV, then write the value. field(IVOA,DBF_MENU) { prompt("INVALID output action") - promptgroup(GUI_OUTPUT) + promptgroup("50 - Output") interest(2) menu(menuIvoa) } field(IVOV,DBF_INT64) { prompt("INVALID output value") - promptgroup(GUI_OUTPUT) + promptgroup("50 - Output") interest(2) } } From f0d7d42ab4bf9e4831aead3108546543f525374b Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 3 May 2017 17:07:06 +0200 Subject: [PATCH 19/25] std: remove SCM keywords from int64in and int64out sources --- src/std/dev/devI64inSoft.c | 3 +-- src/std/dev/devI64outSoft.c | 1 - src/std/rec/int64inRecord.c | 2 -- src/std/rec/int64outRecord.c | 1 - 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/std/dev/devI64inSoft.c b/src/std/dev/devI64inSoft.c index f4e6bce83..d90e48fd6 100644 --- a/src/std/dev/devI64inSoft.c +++ b/src/std/dev/devI64inSoft.c @@ -7,8 +7,7 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* $Revision-Id$ - * +/* * Original Author: Janet Anderson * Date: 09-23-91 */ diff --git a/src/std/dev/devI64outSoft.c b/src/std/dev/devI64outSoft.c index 95f6e266c..f9ac70a7e 100644 --- a/src/std/dev/devI64outSoft.c +++ b/src/std/dev/devI64outSoft.c @@ -7,7 +7,6 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* $Revision-Id$ */ /* * Original Author: Janet Anderson * Date: 09-23-91 diff --git a/src/std/rec/int64inRecord.c b/src/std/rec/int64inRecord.c index 700798c66..892eed23c 100644 --- a/src/std/rec/int64inRecord.c +++ b/src/std/rec/int64inRecord.c @@ -7,8 +7,6 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* $Revision-Id$ */ - /* int64inRecord.c - Record Support Routines for int64in records */ /* * Original Author: Janet Anderson diff --git a/src/std/rec/int64outRecord.c b/src/std/rec/int64outRecord.c index 2c44c39c4..02ebf4791 100644 --- a/src/std/rec/int64outRecord.c +++ b/src/std/rec/int64outRecord.c @@ -7,7 +7,6 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* $Revision-Id$ */ /* * Original Author: Janet Anderson * Date: 9/23/91 From eedf296cd245e3f50ce1d1d687e5ac731af68b1a Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 3 May 2017 17:07:46 +0200 Subject: [PATCH 20/25] std/rec: fix copyright in int64in sources --- src/std/rec/int64inRecord.c | 2 +- src/std/rec/int64inRecord.dbd.pod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/std/rec/int64inRecord.c b/src/std/rec/int64inRecord.c index 892eed23c..dba5bac5c 100644 --- a/src/std/rec/int64inRecord.c +++ b/src/std/rec/int64inRecord.c @@ -1,5 +1,5 @@ /*************************************************************************\ -* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. diff --git a/src/std/rec/int64inRecord.dbd.pod b/src/std/rec/int64inRecord.dbd.pod index 919c3d559..b85c68ae0 100644 --- a/src/std/rec/int64inRecord.dbd.pod +++ b/src/std/rec/int64inRecord.dbd.pod @@ -1,5 +1,5 @@ #************************************************************************* -# Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne +# Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. From 925d03bcec53450d723feee8efb2466eb642b79d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 May 2017 17:54:58 -0400 Subject: [PATCH 21/25] minor --- src/ioc/dbStatic/dbStaticLib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 0ecf20a4f..be382a365 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -3071,7 +3071,7 @@ void dbDumpRecordType(DBBASE *pdbbase,const char *recordTypeName) printf("\n"); printf("indvalFlddes %d name %s\n",pdbRecordType->indvalFlddes, pdbRecordType->pvalFldDes->name); - printf("struct rset * %p rec_size %d\n", + printf("rset * %p rec_size %d\n", (void *)pdbRecordType->prset,pdbRecordType->rec_size); if(recordTypeName) break; } From 1b16c7130b6ac7143ad0c449d2a5e494953f6d78 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 May 2017 17:58:29 -0400 Subject: [PATCH 22/25] std/rec: ioc64in/outRecord typed rset --- src/std/rec/int64inRecord.c | 10 ++++++---- src/std/rec/int64outRecord.c | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/std/rec/int64inRecord.c b/src/std/rec/int64inRecord.c index dba5bac5c..bac4c92f8 100644 --- a/src/std/rec/int64inRecord.c +++ b/src/std/rec/int64inRecord.c @@ -42,8 +42,8 @@ /* Create RSET - Record Support Entry Table*/ #define report NULL #define initialize NULL -static long init_record(int64inRecord *, int); -static long process(int64inRecord *); +static long init_record(dbCommon *, int); +static long process(dbCommon *); #define special NULL #define get_value NULL #define cvt_dbaddr NULL @@ -94,8 +94,9 @@ static void monitor(int64inRecord *prec); static long readValue(int64inRecord *prec); -static long init_record(int64inRecord *prec, int pass) +static long init_record(dbCommon *pcom, int pass) { + int64inRecord *prec = (int64inRecord*)pcom; struct int64indset *pdset; long status; @@ -129,8 +130,9 @@ static long init_record(int64inRecord *prec, int pass) return(0); } -static long process(int64inRecord *prec) +static long process(dbCommon *pcom) { + int64inRecord *prec = (int64inRecord*)pcom; struct int64indset *pdset = (struct int64indset *)(prec->dset); long status; unsigned char pact=prec->pact; diff --git a/src/std/rec/int64outRecord.c b/src/std/rec/int64outRecord.c index 02ebf4791..d63fad7ea 100644 --- a/src/std/rec/int64outRecord.c +++ b/src/std/rec/int64outRecord.c @@ -39,8 +39,8 @@ /* Create RSET - Record Support Entry Table*/ #define report NULL #define initialize NULL -static long init_record(int64outRecord *, int); -static long process(int64outRecord *); +static long init_record(dbCommon *, int); +static long process(dbCommon *); #define special NULL #define get_value NULL #define cvt_dbaddr NULL @@ -92,8 +92,9 @@ static long writeValue(int64outRecord *prec); static void convert(int64outRecord *prec, epicsInt64 value); -static long init_record(int64outRecord *prec, int pass) +static long init_record(dbCommon *pcom, int pass) { + int64outRecord *prec = (int64outRecord*)pcom; struct int64outdset *pdset; long status=0; @@ -123,8 +124,9 @@ static long init_record(int64outRecord *prec, int pass) return(0); } -static long process(int64outRecord *prec) +static long process(dbCommon *pcom) { + int64outRecord *prec = (int64outRecord*)pcom; struct int64outdset *pdset = (struct int64outdset *)(prec->dset); long status=0; epicsInt64 value; From 5e0dc5d1c9d49d3e3b62d83d6a6b152a7447a7de Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 May 2017 18:39:43 -0400 Subject: [PATCH 23/25] ioc/db: dbUnitTest helps support int64 --- src/ioc/db/dbUnitTest.c | 8 ++++++++ src/ioc/db/dbUnitTest.h | 2 ++ src/libCom/misc/epicsTypes.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c index 33d721656..0aebb90ca 100644 --- a/src/ioc/db/dbUnitTest.c +++ b/src/ioc/db/dbUnitTest.c @@ -130,6 +130,8 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap) OP(DBR_USHORT, int, uInt16); OP(DBR_LONG, int, int32); OP(DBR_ULONG, unsigned int, uInt32); + OP(DBR_INT64, long long, int64); + OP(DBR_UINT64, unsigned long long, uInt64); OP(DBR_FLOAT, double, float32); OP(DBR_DOUBLE, double, float64); OP(DBR_ENUM, int, enum16); @@ -218,10 +220,14 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap) OP(DBR_USHORT, int, uInt16, "%d"); OP(DBR_LONG, int, int32, "%d"); OP(DBR_ULONG, unsigned int, uInt32, "%u"); + OP(DBR_INT64, long long, int64, "%lld"); + OP(DBR_UINT64, unsigned long long, uInt64, "%llu"); OP(DBR_FLOAT, double, float32, "%e"); OP(DBR_DOUBLE, double, float64, "%e"); OP(DBR_ENUM, int, enum16, "%d"); #undef OP + default: + testFail("dbGetField(\"%s\", %d) -> unsupported dbf", pv, dbrType); } } @@ -278,6 +284,8 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign OP(DBR_USHORT, unsigned short, "%u"); OP(DBR_LONG, int, "%d"); OP(DBR_ULONG, unsigned int, "%u"); + OP(DBR_INT64, long long, "%lld"); + OP(DBR_UINT64, unsigned long long, "%llu"); OP(DBR_FLOAT, float, "%e"); OP(DBR_DOUBLE, double, "%e"); OP(DBR_ENUM, int, "%d"); diff --git a/src/ioc/db/dbUnitTest.h b/src/ioc/db/dbUnitTest.h index 82954c277..c4526eb04 100644 --- a/src/ioc/db/dbUnitTest.h +++ b/src/ioc/db/dbUnitTest.h @@ -38,6 +38,8 @@ epicsShareFunc void testdbCleanup(void); * * int for DBR_UCHAR, DBR_CHAR, DBR_USHORT, DBR_SHORT, DBR_LONG * unsigned int for DBR_ULONG + * long long for DBF_INT64 + * unsigned long long for DBF_UINT64 * double for DBR_FLOAT and DBR_DOUBLE * const char* for DBR_STRING * diff --git a/src/libCom/misc/epicsTypes.h b/src/libCom/misc/epicsTypes.h index b5a947b43..efc6a91cb 100644 --- a/src/libCom/misc/epicsTypes.h +++ b/src/libCom/misc/epicsTypes.h @@ -82,6 +82,8 @@ typedef union epics_any { epicsEnum16 enum16; epicsInt32 int32; epicsUInt32 uInt32; + epicsInt64 int64; + epicsUInt64 uInt64; epicsFloat32 float32; epicsFloat64 float64; epicsString string; From 2a81e0b3382fe839938721e2dbf56857ec36f5ce Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 3 May 2017 19:18:52 -0400 Subject: [PATCH 24/25] std/rec/test: recMiscTest check in64in/out --- src/std/rec/test/Makefile | 7 ++ src/std/rec/test/epicsRunRecordTests.c | 3 + src/std/rec/test/recMiscTest.c | 88 ++++++++++++++++++++++++++ src/std/rec/test/recMiscTest.db | 10 +++ 4 files changed, 108 insertions(+) create mode 100644 src/std/rec/test/recMiscTest.c create mode 100644 src/std/rec/test/recMiscTest.db diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index 793312f9a..27bce8fcf 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -32,6 +32,13 @@ testHarness_SRCS += arrayOpTest.c TESTFILES += ../arrayOpTest.db TESTS += arrayOpTest +TESTPROD_HOST += recMiscTest +recMiscTest_SRCS += recMiscTest.c +recMiscTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += recMiscTest.c +TESTFILES += ../recMiscTest.db +TESTS += recMiscTest + TESTPROD_HOST += linkRetargetLinkTest linkRetargetLinkTest_SRCS += linkRetargetLinkTest.c linkRetargetLinkTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp diff --git a/src/std/rec/test/epicsRunRecordTests.c b/src/std/rec/test/epicsRunRecordTests.c index 5612917cc..ab76a52a4 100644 --- a/src/std/rec/test/epicsRunRecordTests.c +++ b/src/std/rec/test/epicsRunRecordTests.c @@ -14,6 +14,7 @@ int analogMonitorTest(void); int compressTest(void); +int recMiscTest(void); int arrayOpTest(void); int asTest(void); int linkRetargetLinkTest(void); @@ -26,6 +27,8 @@ void epicsRunRecordTests(void) runTest(compressTest); + runTest(recMiscTest); + runTest(arrayOpTest); runTest(asTest); diff --git a/src/std/rec/test/recMiscTest.c b/src/std/rec/test/recMiscTest.c new file mode 100644 index 000000000..05de0e9d2 --- /dev/null +++ b/src/std/rec/test/recMiscTest.c @@ -0,0 +1,88 @@ +/*************************************************************************\ +* Copyright (c) 2017 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include + +#include "dbAccess.h" +#include "errlog.h" +#include "dbStaticLib.h" +#include "dbUnitTest.h" +#include "testMain.h" + +static +void testint64BeforeInit(void) +{ + const char *S; + DBENTRY dbent; + + /* check dbGet/PutString */ + + testDiag("In %s", EPICS_FUNCTION); + + dbInitEntryFromRecord(testdbRecordPtr("out64"), &dbent); + if(dbFindField(&dbent, "VAL")) + testAbort("Failed to find out64.VAL"); + + S = dbGetString(&dbent); + testOk(S && strcmp(S, "0")==0, "initial value \"%s\"", S); + + testOk1(dbPutString(&dbent, "0x12345678abcdef00")==0); + + S = dbGetString(&dbent); + testOk(S && strcmp(S, "1311768467750121216")==0, "1311768467750121216 \"%s\"", S); + + dbFinishEntry(&dbent); +} + +static +void testint64AfterInit(void) +{ + testDiag("In %s", EPICS_FUNCTION); + + /* check dbGet/PutField and DB links */ + + testdbGetFieldEqual("in64", DBF_UINT64, 0llu); + testdbGetFieldEqual("out64", DBF_UINT64, 0x12345678abcdef00llu); + + testdbPutFieldOk("out64.PROC", DBF_LONG, 1); + + testdbGetFieldEqual("in64", DBF_UINT64, 0x12345678abcdef00llu); + + testdbPutFieldOk("out64.VAL", DBF_UINT64, 0x22345678abcdef00llu); + + testdbPutFieldOk("in64.PROC", DBF_LONG, 1); + + testdbGetFieldEqual("in64", DBF_UINT64, 0x22345678abcdef00llu); +} + +void recTestIoc_registerRecordDeviceDriver(struct dbBase *); + +MAIN(recMiscTest) +{ + testPlan(0); + + testdbPrepare(); + + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); + + recTestIoc_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("recMiscTest.db", NULL, NULL); + + testint64BeforeInit(); + + eltc(0); + testIocInitOk(); + eltc(1); + + testint64AfterInit(); + + testIocShutdownOk(); + + testdbCleanup(); + + return testDone(); +} diff --git a/src/std/rec/test/recMiscTest.db b/src/std/rec/test/recMiscTest.db new file mode 100644 index 000000000..46fc8ae11 --- /dev/null +++ b/src/std/rec/test/recMiscTest.db @@ -0,0 +1,10 @@ + +# check int64in/out + +record(int64in, "in64") { + field(INP , "out64 NPP") +} + +record(int64out, "out64") { + field(OUT , "in64 NPP") +} From ad0695b1192308eb0d172f81f7adbbb7a61261af Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 4 May 2017 09:27:23 +0200 Subject: [PATCH 25/25] std/rec: streamline variable names in int64in/int64out --- src/std/rec/int64inRecord.c | 8 ++++---- src/std/rec/int64outRecord.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/std/rec/int64inRecord.c b/src/std/rec/int64inRecord.c index bac4c92f8..85063028d 100644 --- a/src/std/rec/int64inRecord.c +++ b/src/std/rec/int64inRecord.c @@ -94,9 +94,9 @@ static void monitor(int64inRecord *prec); static long readValue(int64inRecord *prec); -static long init_record(dbCommon *pcom, int pass) +static long init_record(dbCommon *pcommon, int pass) { - int64inRecord *prec = (int64inRecord*)pcom; + int64inRecord *prec = (int64inRecord*)pcommon; struct int64indset *pdset; long status; @@ -130,9 +130,9 @@ static long init_record(dbCommon *pcom, int pass) return(0); } -static long process(dbCommon *pcom) +static long process(dbCommon *pcommon) { - int64inRecord *prec = (int64inRecord*)pcom; + int64inRecord *prec = (int64inRecord*)pcommon; struct int64indset *pdset = (struct int64indset *)(prec->dset); long status; unsigned char pact=prec->pact; diff --git a/src/std/rec/int64outRecord.c b/src/std/rec/int64outRecord.c index d63fad7ea..ecbe52ce8 100644 --- a/src/std/rec/int64outRecord.c +++ b/src/std/rec/int64outRecord.c @@ -92,9 +92,9 @@ static long writeValue(int64outRecord *prec); static void convert(int64outRecord *prec, epicsInt64 value); -static long init_record(dbCommon *pcom, int pass) +static long init_record(dbCommon *pcommon, int pass) { - int64outRecord *prec = (int64outRecord*)pcom; + int64outRecord *prec = (int64outRecord*)pcommon; struct int64outdset *pdset; long status=0; @@ -124,9 +124,9 @@ static long init_record(dbCommon *pcom, int pass) return(0); } -static long process(dbCommon *pcom) +static long process(dbCommon *pcommon) { - int64outRecord *prec = (int64outRecord*)pcom; + int64outRecord *prec = (int64outRecord*)pcommon; struct int64outdset *pdset = (struct int64outdset *)(prec->dset); long status=0; epicsInt64 value;