diff --git a/devsupApp/src/Makefile b/devsupApp/src/Makefile index d995155..72a68f8 100644 --- a/devsupApp/src/Makefile +++ b/devsupApp/src/Makefile @@ -34,6 +34,8 @@ _dbapi_SYS_LIBS_WIN32 += ws2_32 Advapi32 Dbghelp PY += devsup/__init__.py PY += devsup/_dbapi.dbd +PY += devsup/_int64.dbd +PY += devsup/_lsilso.dbd PY += devsup/db.py PY += devsup/dset.py PY += devsup/hooks.py diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 94da410..f2fc1f9 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -304,8 +304,8 @@ static PyObject* pyField_putval(pyField *self, PyObject* args) OP(LONG, epicsInt32, PyInt_AsLong); OP(ULONG, epicsUInt32, PyInt_AsLong); #ifdef HAVE_INT64 - OP(INT64, epicsInt32, PyLong_AsLongLong); - OP(UINT64, epicsUInt32, PyLong_AsLongLong); + OP(INT64, epicsInt64, PyLong_AsLongLong); + OP(UINT64, epicsUInt64, PyLong_AsLongLong); #endif OP(FLOAT, epicsFloat32,PyFloat_AsDouble); OP(DOUBLE,epicsFloat64,PyFloat_AsDouble); @@ -322,11 +322,15 @@ static PyObject* pyField_putval(pyField *self, PyObject* args) fld = PyString_AsString(val); #endif if(fld) { - strncpy(dest, fld, MAX_STRING_SIZE); - dest[MAX_STRING_SIZE-1]='\0'; + strncpy(dest, fld, self->addr.field_size); + dest[self->addr.field_size-1]='\0'; } else { dest[0] = '\0'; } + if (self->addr.special == SPC_MOD) + /* This is needed for long string support. */ + if (prset = dbGetRset(&self->addr)) + prset->special(&self->addr, 1); #if PY_MAJOR_VERSION >= 3 Py_DECREF(data); #endif diff --git a/devsupApp/src/devsup/__init__.py b/devsupApp/src/devsup/__init__.py index 8bb090b..807739e 100644 --- a/devsupApp/src/devsup/__init__.py +++ b/devsupApp/src/devsup/__init__.py @@ -77,6 +77,14 @@ def _init(iocMain=False): dirname = os.path.dirname(__file__) dbd_name = dirname + "/_dbapi.dbd" _dbapi.dbReadDatabase(dbd_name) + if epicsver >= (3, 15, 0, 2): + # Long strings are impletemented. + dbd_name = dirname + "/_lsilso.dbd" + _dbapi.dbReadDatabase(dbd_name) + if epicsver >= (3, 16, 1, 0): + # Long ints are impletemented. + dbd_name = dirname + "/_int64.dbd" + _dbapi.dbReadDatabase(dbd_name) _dbapi._dbd_setup() def _fini(iocMain=False): diff --git a/devsupApp/src/devsup/_dbapi.dbd b/devsupApp/src/devsup/_dbapi.dbd index b42785a..32aae22 100644 --- a/devsupApp/src/devsup/_dbapi.dbd +++ b/devsupApp/src/devsup/_dbapi.dbd @@ -1,6 +1,7 @@ device(longin, INST_IO, pydevsupComIn, "Python Device") device(longout, INST_IO, pydevsupComOut, "Python Device") +device(calcout, INST_IO, pydevsupComOut, "Python Device") device(ai, INST_IO, pydevsupComIn, "Python Device") device(ao, INST_IO, pydevsupComOut, "Python Device") diff --git a/devsupApp/src/devsup/_int64.dbd b/devsupApp/src/devsup/_int64.dbd new file mode 100644 index 0000000..120fb64 --- /dev/null +++ b/devsupApp/src/devsup/_int64.dbd @@ -0,0 +1,2 @@ +device(int64in, INST_IO, pydevsupComIn, "Python Device") +device(int64out, INST_IO, pydevsupComOut, "Python Device") diff --git a/devsupApp/src/devsup/_lsilso.dbd b/devsupApp/src/devsup/_lsilso.dbd new file mode 100644 index 0000000..761ef5b --- /dev/null +++ b/devsupApp/src/devsup/_lsilso.dbd @@ -0,0 +1,2 @@ +device(lsi, INST_IO, pydevsupComIn, "Python Device") +device(lso, INST_IO, pydevsupComOut, "Python Device") \ No newline at end of file diff --git a/devsupApp/src/devsup/test/test_db.py b/devsupApp/src/devsup/test/test_db.py index 2c7ea52..07d0fbd 100644 --- a/devsupApp/src/devsup/test/test_db.py +++ b/devsupApp/src/devsup/test/test_db.py @@ -2,6 +2,7 @@ import os import unittest import tempfile +import time import numpy from numpy.testing import assert_array_almost_equal, assert_array_equal @@ -129,7 +130,6 @@ def test_wf_string(self): assert_array_equal(rec.VAL, numpy.asarray(["zero", "", "one", "This is a really long string which shoul", "", "last"], dtype='S40')) - class TestDset(IOCHelper): db = """ record(longin, "rec:li") { @@ -163,6 +163,106 @@ def test_increment(self): with rec: self.assertEqual(rec.VAL, 1) self.assertEqual(rec.UDF, 0) + +class TestLongStringField(IOCHelper): + db = """ + record(lsi, "rec:lsi") { + field(SIZV, 128) + field(SCAN, "I/O Intr") + } + record(lso, "rec:lso") { + field(SIZV, 128) + field(DOL, "rec:lsi.VAL$") + field(OMSL, "closed_loop") + } + """ + if _dbapi.epicsver[:4] < (3, 15, 0, 2): + # Long strings not impletemented yet. + db = None + + def test_lsilso(self): + if _dbapi.epicsver[:4] < (3, 15, 0, 2): + # Long strings not impletemented yet. + return + + lsi = getRecord("rec:lsi") + lso = getRecord("rec:lso") + + with lsi: + self.assertEqual(lsi.VAL, "") + + lsi.VAL = "test" + self.assertEqual(lsi.VAL, "test") + + lsi.VAL = "" + self.assertEqual(lsi.VAL, "") + + # does not truncate + lsi.VAL = "This is a really long string which should NOT be truncated" + self.assertEqual(lsi.VAL, "This is a really long string which should NOT be truncated") + + lso.scan() + time.sleep(0.01) # The linked value needs a small amount of time to update. + + with lso: + self.assertEqual(lso.VAL, lsi.VAL) + +class TestInt64Field(IOCHelper): + db = """ + record(int64in, "rec:in64") { + field(SCAN, "I/O Intr") + } + record(int64out, "rec:out64") { + field(DOL, "rec:in64.VAL") + field(OMSL, "closed_loop") + } + """ + if _dbapi.epicsver[:4] < (3, 16, 1, 0): + # Long ints not implemented yet. + db = None + + def testint64(self): + if _dbapi.epicsver[:4] < (3, 16, 1, 0): + # Long ints not implemented yet. + return + in64 = getRecord("rec:in64") + out64 = getRecord("rec:out64") + + with in64: + self.assertEqual(in64.VAL, 0) + + in64.VAL = 42 + self.assertEqual(in64.VAL, 42) + + in64.VAL = 0x7FFFFFFFFFFFFFFE + self.assertEqual(in64.VAL, 0x7FFFFFFFFFFFFFFE) + + in64.VAL = 0x7FFFFFFFFFFFFFFF + self.assertEqual(in64.VAL, 0x7FFFFFFFFFFFFFFF) + + out64.scan() + time.sleep(0.01) # The linked value needs a small amount of time to update. + + with out64: + self.assertEqual(out64.VAL, in64.VAL) + +class TestCalcOutRecord(IOCHelper): + db = """ + record(calcout, "rec:calcout") { + field(OOPT, "On Change") + field(INPA, "0") + field(INPB, "0") + field(CALC, "A+B") + } + """ + def test_calcoutrecord(self): + rec = getRecord('rec:calcout') + self.assertEqual(rec.VAL, 0) + rec.A = 40 + rec.B = 2 + self.assertEqual(rec.scan(sync=True), 0) + self.assertEqual(rec.VAL, 42) + class TestAlarm(IOCHelper):