Fix scalar link initialization from hex constants
Partially fixes LP: #1699445 Includes regression tests, with TODO for arrays which are still broken and need a full JSON5 parser to fix.
This commit is contained in:
+105
-3
@@ -16,18 +16,121 @@
|
||||
#include <string.h>
|
||||
|
||||
#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,
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -13,11 +13,24 @@
|
||||
#include <waveformRecord.h>
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user