diff --git a/src/ioc/db/dbConstLink.c b/src/ioc/db/dbConstLink.c index 0bdc70f92..ffedce43f 100644 --- a/src/ioc/db/dbConstLink.c +++ b/src/ioc/db/dbConstLink.c @@ -16,18 +16,121 @@ #include #include "dbDefs.h" +#include "epicsStdlib.h" #define epicsExportSharedSymbols #include "dbAccessDefs.h" #include "dbAddr.h" #include "dbCommon.h" #include "dbConstLink.h" -#include "dbConvertFast.h" #include "dbConvertJSON.h" #include "dbFldTypes.h" #include "dbLink.h" #include "link.h" +/**************************** Convert functions ****************************/ + +/* The difference between these and dbFastConvert is that constants + * may contain hex numbers, whereas database conversions can't. + */ + +/* Copy to STRING */ +static long cvt_st_st(const char *from, void *pfield, const dbAddr *paddr) +{ + char *to = pfield; + 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; +} + +/* Most integer conversions are identical */ +#define cvt_st_int(TYPE) static long \ +cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \ + epics##TYPE *to = pfield; \ + char *end; \ +\ + if (*from == 0) { \ + *to = 0; \ + return 0; \ + } \ + return epicsParse##TYPE(from, to, 0, &end); \ +} + +/* Instanciate for CHAR, UCHAR, SHORT, USHORT and LONG */ +cvt_st_int(Int8) +cvt_st_int(UInt8) +cvt_st_int(Int16) +cvt_st_int(UInt16) +cvt_st_int(Int32) + +/* Conversion for ULONG is different... */ +static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr) +{ + epicsUInt32 *to = pfield; + char *end; + long status; + + if (*from == 0) { + *to = 0; + return 0; + } + status = epicsParseUInt32(from, to, 0, &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 ULONG fields are DOUBLE. + */ + double dval; + + status = epicsParseFloat64(from, &dval, &end); + if (!status && + dval >=0 && + dval <= ULONG_MAX) + *to = dval; + } + return status; +} + +/* Instanciate for INT64 and UINT64 */ +cvt_st_int(Int64) +cvt_st_int(UInt64) + + +/* Float conversions are identical */ +#define cvt_st_float(TYPE) static long \ +cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \ + epics##TYPE *to = pfield; \ + char *end; \ +\ + if (*from == 0) { \ + *to = 0; \ + return 0; \ + } \ + return epicsParse##TYPE(from, to, &end); \ +} + +/* Instanciate for FLOAT32 and FLOAT64 */ +cvt_st_float(Float32) +cvt_st_float(Float64) + + +static long (*convert[DBF_DOUBLE+1])(const char *, void *, const dbAddr *) = { + cvt_st_st, + cvt_st_Int8, cvt_st_UInt8, + cvt_st_Int16, cvt_st_UInt16, + cvt_st_Int32, cvt_st_UInt32, + cvt_st_Int64, cvt_st_UInt64, + cvt_st_Float32, cvt_st_Float64 +}; + /***************************** Constant Links *****************************/ /* Forward definition */ @@ -65,8 +168,7 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer) return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq); } - return dbFastPutConvertRoutine[DBR_STRING][dbrType] - (pstr, pbuffer, NULL); + return convert[dbrType](pstr, pbuffer, NULL); } static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size, diff --git a/src/std/rec/test/regressHex.db b/src/std/rec/test/regressHex.db new file mode 100644 index 000000000..83f6916e9 --- /dev/null +++ b/src/std/rec/test/regressHex.db @@ -0,0 +1,28 @@ +record(ai, "ai1") { + field(INP, 0x10) +} +record(longin, "li1") { + field(INP, 0x10) +} +record(mbbiDirect, "mi1") { + field(INP, 0x10) + field(NOBT, 8) +} +record(aSub, "as1") { + field(INPA, 0x10) + field(FTA, "CHAR") + field(INPB, 0x10) + field(FTB, "UCHAR") + field(INPC, 0x10) + field(FTC, "SHORT") + field(INPD, 0x10) + field(FTD, "USHORT") + field(INPE, 0x10) + field(FTE, "LONG") + field(INPF, 0x10) + field(FTF, "ULONG") + field(INPG, 0x10) + field(FTG, "FLOAT") + field(INPH, 0x10) + field(FTH, "DOUBLE") +} diff --git a/src/std/rec/test/regressTest.c b/src/std/rec/test/regressTest.c index ccbe53189..ecbced5d0 100644 --- a/src/std/rec/test/regressTest.c +++ b/src/std/rec/test/regressTest.c @@ -13,11 +13,24 @@ #include /* - * Test the some identified regressions + * Tests for specific regressions */ void regressTest_registerRecordDeviceDriver(struct dbBase *); +static +void startRegressTestIoc(const char *dbfile) +{ + testdbPrepare(); + testdbReadDatabase("regressTest.dbd", NULL, NULL); + regressTest_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase(dbfile, NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); +} + /* * https://bugs.launchpad.net/epics-base/+bug/1577108 */ @@ -28,21 +41,11 @@ void testArrayLength1(void) calcoutRecord *precco; double *pbuf; - testdbPrepare(); - - testdbReadDatabase("regressTest.dbd", NULL, NULL); - - regressTest_registerRecordDeviceDriver(pdbbase); - - testdbReadDatabase("regressArray1.db", NULL, NULL); + startRegressTestIoc("regressArray1.db"); precwf = (waveformRecord*)testdbRecordPtr("wf"); precco = (calcoutRecord*)testdbRecordPtr("co"); - eltc(0); - testIocInitOk(); - eltc(1); - dbScanLock((dbCommon*)precwf); pbuf = (double*)precwf->bptr; dbScanUnlock((dbCommon*)precwf); @@ -65,9 +68,37 @@ void testArrayLength1(void) testdbCleanup(); } +/* + * https://bugs.launchpad.net/epics-base/+bug/1699445 + */ +static +void testHexConstantLinks(void) +{ + startRegressTestIoc("regressHex.db"); + + testdbGetFieldEqual("ai1", DBR_LONG, 0x10); + testdbGetFieldEqual("li1", DBR_LONG, 0x10); + testdbGetFieldEqual("mi1", DBR_LONG, 0x10); + testTodoBegin("Needs JSON5 for hex arrays"); + testdbGetFieldEqual("as1.A", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.B", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.C", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.D", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.E", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.F", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.G", DBR_LONG, 0x10); + testdbGetFieldEqual("as1.H", DBR_LONG, 0x10); + testTodoEnd(); + + testIocShutdownOk(); + testdbCleanup(); +} + + MAIN(regressTest) { - testPlan(5); + testPlan(16); testArrayLength1(); + testHexConstantLinks(); return testDone(); }